[英]How do I compile & instantiate a Java class from source programmatically when it has project dependencies?
[英]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.