在Java应用程序运行时定义一个类

17
在Java中,是否可以在应用程序运行时动态创建类定义,然后创建该类的对象?
例如,正在运行的应用程序将读取包含要包括在新类中的成员列表的文本文件。然后,应用程序将根据成员列表定义一个类定义,接着实例化它。

25
这就是SkyNet启动的方式。 - TheTXI
8
如果Skynet用Java编写,它需要的内存太多了,永远不会构成威胁。 - Pesto
4
SkyNet会建立一个更大的集群来运行。它使用Java编写是有道理的,因为SkyNet和Java都可能成为人类终结的原因。 - TheTXI
4
我一直认为SkyNet是用Perl编写的。那么它需要做的就是输出随机标点符号并将其导入Perl解释器以实现进化。 - Pesto
1
纯属好奇,你是想用这种方法解决什么问题吗?还是这个问题只是学术性质的? - James McMahon
@nemo:主要是出于好奇。我正在编写一个Java程序,它将输出一个Java类定义,我可能不需要即时创建类的对象,但认为这样做很酷... - Lehane
11个回答

11

理论上来说是可以做到的,因为你的类文件最终是一个字节数组!你可以使用 defineClass(String, byte[], int, int) 方法获取一个 Class 实例,然后通过反射实例化对象。

在实际应用中,你可以使用类似 CGLibjavaassist 的工具。

你也可以采取生成 Java 代码文件、调用编译器、加载文件的繁琐方式。


2

您可以使用 ASM 动态生成类。


1
你可以通过将新类的代码写入文件,然后在该文件上调用Java编译器,并使用类加载器动态加载该类到正在运行的应用程序中来实现此操作。Apache Tomcat对其JSP页面执行此操作;它获取代码,对其进行一些更改,在类的中间包装一个try/catch块,然后将其写入文件系统,编译它,并使用类加载器获取并使用它来处理请求。

1

当然可以。例如,可以查看这个文章


1

ASM 可能是 Java 最低层次的字节码库。这使得它非常困难,但也非常强大。我建议阅读 ASM 的文档 (PDF),以真正理解 Java 中的字节码生成方式。该文档还解释了如何在类加载器中加载字节码(另一个难点)。

之后,您可以使用其中一个更高级别的库,如果它能让您的生活更轻松,并理解它们所做的事情。对于许多情况,例如生成代理,CGLIB 是有用且易于使用的。对于更强大的功能,许多人提到 Javassist(我没有使用过 - CGLIB 和 ASM 对我来说已经很好了)。


1
也许最简单的解决方案(不需要额外的库)是使用Java 6附带的Java编译器API。您只需能够生成.java文件,编译,然后执行Class.forName()即可。

0

或许有点过度,Apache BCEL(字节码工程库)可用于在运行时创建class文件。

虽然我自己没有尝试过,但可以想象,在运行时可以创建一个类,加载它并实例化它。


0

是的,这是可能的。

您可以使用Javassist在运行时创建类,通过定义类的主体并使javassist编译您的新类。

Javassist具有自定义编译器,根据您的类定义创建字节码。它有一些特殊的处理方式,但使用此库非常容易和直观。

Javassist用于JBoss,我认为这是一个很好的参考 :)

同样可以使用BCEL实现相同的功能,但这更加困难(但是以这种方式,您可以更好地控制所生成的内容)。


0

如果你必须这样做,你可能可以使用JRuby、JPython或Groovy之类的工具。

如果你感觉特别虐待自己,你可以看看BCEL


0
如果你想使用Java和元编程,可以使用Groovy

嗨,Stefan,那么Groovy可以帮助在运行时动态编译Java类并实例化它吗?你有关于如何做到这一点的任何指针吗? - Sergio

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接