2010-05-31 18 views
59

Tôi có tên lớp được lưu trữ trong tệp thuộc tính. Tôi biết rằng các cửa hàng lớp học sẽ thực hiện IDynamicLoad. Làm cách nào để nhanh chóng khởi động lớp học?Làm cách nào để lập trình và khởi tạo một lớp Java một cách có lập trình?

Ngay bây giờ tôi có

 Properties foo = new Properties(); 
    foo.load(new FileInputStream(new File("ClassName.properties"))); 
    String class_name = foo.getProperty("class","DefaultClass"); 
    //IDynamicLoad newClass = Class.forName(class_name).newInstance(); 

Liệu newInstance chỉ tải biên soạn .class file? Làm cách nào để tải một Lớp Java không được biên dịch?

Trả lời

118

Làm cách nào để tải một Lớp Java chưa được biên dịch?

Bạn cần phải biên dịch nó trước. Điều này có thể được thực hiện theo chương trình với javax.tools API. Điều này chỉ yêu cầu JDK đang được cài đặt tại máy cục bộ trên đầu trang của JRE.

Dưới đây là một ví dụ Kickoff cơ bản (rời khỏi ngoại lệ rõ ràng xử lý sang một bên):

// Prepare source somehow. 
String source = "package test; public class Test { static { System.out.println(\"hello\"); } public Test() { System.out.println(\"world\"); } }"; 

// Save source in .java file. 
File root = new File("/java"); // On Windows running on C:\, this is C:\java. 
File sourceFile = new File(root, "test/Test.java"); 
sourceFile.getParentFile().mkdirs(); 
Files.write(sourceFile.toPath(), source.getBytes(StandardCharsets.UTF_8)); 

// Compile source file. 
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
compiler.run(null, null, null, sourceFile.getPath()); 

// Load and instantiate compiled class. 
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { root.toURI().toURL() }); 
Class<?> cls = Class.forName("test.Test", true, classLoader); // Should print "hello". 
Object instance = cls.newInstance(); // Should print "world". 
System.out.println(instance); // Should print "[email protected]". 

nào mang lại như

hello 
world 
[email protected] 

sử dụng tiếp theo sẽ dễ dàng hơn nếu những lớp implements một giao diện nào đó mà đã trong classpath.

SomeInterface instance = (SomeInterface) cls.newInstance(); 

Nếu không, bạn cần liên quan đến Reflection API để truy cập và gọi các trường/phương thức (không xác định).


Điều đó nói rằng và không liên quan đến các vấn đề thực tế:

properties.load(new FileInputStream(new File("ClassName.properties"))); 

Cho java.io.File dựa vào thư mục làm việc hiện nay là công thức cho tính di động gặp khó khăn. Đừng làm thế. Đặt tệp đó trong classpath và sử dụng ClassLoader#getResourceAsStream() với đường dẫn tương đối classpath.

properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("ClassName.properties")); 
+0

Chỉ cần một câu hỏi về chủ đề tắt. Tôi nhận được một null khi tôi tải các thuộc tính theo cách của bạn nhưng tôi nhận được các thuộc tính khi tôi làm điều đó Foo.class.getResourceAsStream()? Bạn có thể giúp tôi hiểu mã của bạn không? Cảm ơn bạn. – unj2

+0

Tệp thuộc tính đó dường như được đặt trong cùng một gói với lớp 'Foo'. Như đã nói, bạn cần chỉ định đường dẫn tương đối classpath, ví dụ: 'com/example/filename.properties'. Nhưng nếu bạn có thể đảm bảo rằng tệp thuộc tính luôn nằm trong cùng một gói với lớp 'Foo', thì' Class # getResourceAsStream() 'cũng được. Bạn sẽ chỉ bỏ lỡ khả năng để externalize các propertiesfile bên ngoài ứng dụng để nó có thể được sửa đổi mà không cần sửa đổi/đóng gói lại ứng dụng. – BalusC

+0

'Files.write (nguồn, sourceFile, StandardCharsets.UTF_8);' không biên dịch cho tôi. Tôi nghĩ bạn muốn 'Files.write (sourceFile.toPath(), source.getBytes());'. –

4

Mã nhận xét của bạn là chính xác nếu bạn biết rằng lớp đó có công cụ xây dựng no-arg công khai. Bạn chỉ cần bỏ kết quả, vì trình biên dịch không thể biết rằng lớp đó thực tế sẽ thực hiện IDynamicLoad. Vì vậy:

IDynamicLoad newClass = (IDynamicLoad) Class.forName(class_name).newInstance(); 

Tất nhiên, lớp học phải được biên soạn và trên đường dẫn để làm việc.

Nếu bạn đang tìm cách tự động biên dịch một lớp từ mã nguồn, đó là toàn bộ ấm đun nước khác của cá.

5

Trong bối cảnh đó là câu trả lời BalusC, nhưng một wrapper tự động hơn chút là ở đây trong đoạn mã này từ phân phối Kilim tôi. https://github.com/kilim/kilim/blob/master/src/kilim/tools/Javac.java

Cần danh sách các chuỗi chứa nguồn Java, trích xuất gói và tên lớp/giao diện công khai và tạo phân cấp thư mục/tệp tương ứng trong thư mục tmp. Sau đó nó chạy trình biên dịch java trên nó, và trả về một danh sách các tên, các cặp classfile (cấu trúc ClassInfo).

Giúp bản thân bạn nhập mã. Nó được cấp phép MIT.

+0

Điều gì xảy ra nếu quá trình biên dịch thất bại? –