2011-10-08 31 views
8

Tôi đang làm việc trên lớp Trình tải cấu hình để tôi có thể thay đổi tham số của chương trình thông qua tệp văn bản bên ngoài (config.txt) thay vì phải biên dịch lại mã của tôi bằng mọi thay đổi mà tôi thực hiện.Cách thích hợp để sử dụng phản chiếu để khởi tạo các đối tượng của các lớp không xác định khi chạy là gì?

Đã được đề xuất rằng tôi sử dụng Phản chiếu của Java để thực hiện việc này, nhưng tôi hơi bối rối về cách tôi thực sự có thể triển khai điều này.

Tôi đã có thể trích xuất thành công tên lớp và các đối số cho hàm tạo của nó từ tệp văn bản của tôi, nhưng làm cách nào để chuyển từ đối tượng này sang đối tượng đã được khởi tạo?

đây là những gì tôi có các phương pháp của tôi cho đến nay:

public void loadObject(String classString, HashMap hm) 
    { 
    String className = props.getProperty(classString); 
    Class c = Class.forName(className); 
    } 

classString là một chuỗi chứa tên của lớp, và hm là một hashmap nơi bản đồ thông số constructor lớp để các giá trị dự định của họ.

I.e., đối với class Foo (int xPos, float yPos), "xPos" sẽ ánh xạ tới một chuỗi các bản đồ int, và "yPos" dự định tới một chuỗi phao dự định. Tôi muốn để có thể quay lại, new Foo(hm.get"xPos".toInt, hm.get"yPost".toFloat), nhưng tôi không chắc chắn cách sử dụng động một hàm tạo như vậy (vấn đề là, có nhiều lớp có thể - có lẽ nó là bar thay vì foo chẳng hạn).

Tôi biết rằng có thể thực hiện if/else dựa trên classString và chỉ cần gọi hàm tạo thích hợp sau khi xác định theo cách đó, nhưng tôi đang tìm cách tạo mã mở rộng hơn mà không cần phải viết lại mỗi khi tôi thêm một lớp mới vào chương trình.

Tất cả các đối tượng có thể thừa kế từ một đối tượng chính.

Trả lời

14

Bạn sẽ sử dụng Class.getConstructor(Class<?>... parameterTypes) để tham chiếu đến hàm tạo, theo sau là Constructor.newInstance(Object... initargs).

Tuy nhiên, tôi khuyên bạn nên xem xét khung tiêm phụ thuộc như Spring hoặc Guice vì nó giống như những gì bạn đang tạo là phiên bản cơ bản về những gì họ làm.

Theo yêu cầu để mở rộng câu trả lời này:

Class c = Class.forName(name); 
Constructor ctor = c.getConstructor(Integer.class, Integer.class); 
Integer param1 = hm.get("xPos") ...; 
Integer param2 = hm.get("yPos") ...; 
Object instanceOfTheClass = ctor.newInstance(param1, param2); 

Dĩ nhiên thay vì param1param2 bạn sẽ tạo ra một mảng các đối số dựa trên những gì đã ở file đầu vào (cùng đi cho các đối số getConstructor()) vv

+0

Tôi e rằng tôi không hiểu dòng đầu tiên của mã giả của bạn.Tôi không quen với Reflection chút nào, vì vậy tôi không chắc mã của bạn thực sự là * đang làm gì *. Nó sẽ có thể mở rộng câu trả lời của bạn một chút? –

+0

Ồ, được rồi, vì vậy, để làm theo ví dụ của tôi ở trên, Foo.GetConstructor sẽ trả về một mảng (int, float)? Và sau đó từ đó tôi có thể đúc đúng đối tượng vào initargs cho Constructor.newInstance? –

+1

+1 để sử dụng giải pháp hiện có cho quản lý bean –

1
Class<?> clazz = MyClass.class; 
Constructor<?> ctor = clazz.getConstructor(/* Array of Classes the constructor takes */); 
ctor.newInstance(/* arguments the constructor takes */); 
3

Dưới đây là một ví dụ về làm việc đó từ đối số chương trình:

01.
import java.lang.reflect.Constructor; 
import java.util.*; 

public class InstantiateWithReflectionIncludingArgs { 
    public static void main(String[] args) throws Exception { 
     String className = args[0]; 
     List<Object> argList = new ArrayList<Object>(); 
     if (args.length > 1) { 
      argList.addAll(Arrays.asList(args).subList(1, args.length)); 
     } 
     Class c = Class.forName(className); 
     List<Class<?>> argTypes = new ArrayList<Class<?>>(); 
     for (Object arg : argList) { 
      argTypes.add(arg.getClass()); 
     } 
     Constructor constructor = c.getConstructor(
      argTypes.toArray(new Class<?>[argTypes.size()])); 
     Object o = constructor.newInstance(
      argList.toArray(new Object[argList.size()])); 
     System.out.println("Created a " + o.getClass() + ": " + o); 
    } 
} 

Đương nhiên, argList chỉ có thể có chuỗi trong trường hợp này vì chúng được kéo từ String[], nhưng bạn có thể thêm arg của bất kỳ loại nào. Lưu ý rằng constructor args là vị trí, không được đặt tên, vì vậy các tên trong bản đồ sẽ không làm bạn tốt. Họ cần phải theo đúng thứ tự.

Hãy thử chạy và chuyển "java.util.Date" làm đối số.

Các vấn đề liên quan