如何以编程方式编译和示例化Java类?

b4qexyjb  于 2023-02-28  发布在  Java
关注(0)|答案(3)|浏览(165)

我把类名存储在一个属性文件中。我知道类存储将实现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类?

hyrbngr7

hyrbngr71#

  • 如何加载未编译的Java类?*

您需要先编译它,这可以通过javax.tools API以编程方式完成,这只需要在本地机器上安装JDK,在JRE之上即可。
下面是一个基本的启动示例(将明显的异常处理放在一边):

// 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 = Files.createTempDirectory("java").toFile();
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.getDeclaredConstructor().newInstance(); // Should print "world".
System.out.println(instance); // Should print "test.Test@hashcode".

其收益为

hello
world
test.Test@cafebabe

如果这些类implements具有已经存在于类路径中的特定接口,那么进一步的使用将更加容易。

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

否则,您需要使用Reflection API来访问和调用(未知的)方法/字段。
也就是说,与实际问题无关:

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

java.io.File依赖于当前工作目录会带来移植性问题,但不要这样做,将该文件放在类路径中,并使用ClassLoader#getResourceAsStream()的类路径相对路径。

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

mwyxok5s2#

与BalusC的回答相同,但在我的kilim发行版中的这段代码中有一个更自动的 Package 器。https://github.com/kilim/kilim/blob/master/src/kilim/tools/Javac.java
它获取包含Java源代码的字符串列表,提取包和公共类/接口名称,并在tmp目录中创建相应的目录/文件层次结构,然后在其上运行Java编译器,并返回名称和类文件对的列表(ClassInfo结构)。
请随意使用密码,这是麻省理工学院授权的.

xbp102n0

xbp102n03#

如果你知道这个类有一个公共的无参数构造函数,那么你的注解代码就是正确的,你只需要强制转换结果,因为编译器不知道这个类实际上会实现IDynamicLoad,所以:

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

当然,类必须经过编译,并且必须位于类路径上才能工作。
如果您希望从源代码动态编译一个类,那就完全是另一回事了。

相关问题