簡體   English   中英

如何以編程方式編譯和實例化 Java 類?

[英]How do I programmatically compile and instantiate a Java class?

我將類名存儲在屬性文件中。 我知道類存儲將實現 IDynamicLoad。 如何動態實例化類?

現在我有

     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();

newInstance 是否只加載已編譯的 .class 文件? 如何加載未編譯的 Java 類?

如何加載未編譯的 Java 類?

你需要先編譯它。 這可以通過javax.tools API以編程方式完成。 這只需要在 JRE 之上的本地機器上安裝JDK

這是一個基本的啟動示例(將明顯的異常處理放在一邊):

// 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 "test.Test@hashcode".

哪個產生像

hello
world
test.Test@ab853b

如果這些類implements了某個已經在類路徑中的接口,那么進一步使用會更容易。

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

否則,您需要使用反射 API來訪問和調用(未知)方法/字段。


也就是說,與實際問題無關:

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

java.io.File依賴於當前工作目錄會導致可移植性問題。 不要那樣做。 將該文件放在類路徑中,並使用ClassLoader#getResourceAsStream()和類路徑相對路徑。

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

與 BalusC 的回答相同,但在我的 kilim 發行版中的這段代碼中,這里有一個更自動的包裝器。 https://github.com/kilim/kilim/blob/master/src/kilim/tools/Javac.java

它采用包含 Java 源代碼的字符串列表,提取包和公共類/接口名稱,並在 tmp 目錄中創建相應的目錄/文件層次結構。 然后在其上運行 java 編譯器,並返回名稱、類文件對(ClassInfo 結構)的列表。

幫助自己編寫代碼。 它是 MIT 許可的。

如果您知道該類具有公共無參數構造函數,則您注釋的代碼是正確的。 您只需要轉換結果,因為編譯器無法知道該類實際上會實現IDynamicLoad 所以:

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

當然,類必須被編譯並在類路徑上才能工作。

如果您希望從源代碼動態編譯一個類,那完全是另一回事。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM