如何在Java中动态创建类

23

我不知道这是否可能。不管怎样,这是我的问题: 我想创建一个具有数据库表模式的类,例如假设我有一个表

id - unsigned int 
username - varchar(128)
password - varchar(128)

假设我可以从我的数据库中查询这些数据。我想要做的是动态创建(当然,实例化)一个Java类,它应该像这样:

public class User{
    private unsigned int id;
    private String username;
    private String password;
}

(实际上是我的表的ActiveRecord

你能帮我开始这个吗?谢谢。

11个回答

18

从技术上讲,您可以通过字节码操作库(CGLIB、javassist、asm、bcel等)来实现。

然而,这不是Java的“哲学”。Java是静态类型的,因此最好在运行时之前创建类。

查看hibernate/eclipseLink以了解Java ORM——一种将表映射到对象的方法。


18

如果有一个动态创建和实例化的类,而您的其他代码却不知道它,您会怎么做?

对于像Java这样的静态类型语言,拥有这样的类几乎没有意义。另一方面,大多数ORM框架(例如Hibernate)都配备了工具,可以从数据库模式静态生成类。


2
一个使用案例是生成一个实现接口的类,你的静态代码知道这个接口。我正在研究这个主题,因为我们有一个应用程序针对混合数据库模式运行,所以列可能存在也可能不存在。 - Snekse
我只是试图回答这样一个动态生成类可能用于什么的问题。我们即将尝试类似的事情,但在走向.reflect.Proxy路径或类似路径之前,我认为我们会先研究一下Groovy。 - Snekse
另一个情况是生成一个带有某些注释的类,例如用作ApplicationContext的附加配置类。 - dtortola
@Troyseph:我的回答适用于问题的特定场景。一个类会继承什么,使得它的字段(这些字段是从数据库模式生成的,并且对代码的其余部分不可见)在任何方面都有用呢? - Michael Borgwardt
@MichaelBorgwardt 我理解你的观点,你需要创建overriden方法来了解这些变量的含义...我猜你不可能从模式中生成它们!赞扬你的快速回应,我刚刚注意到你的答案已经有一段时间了! - Troyseph
显示剩余2条评论

6

我认为你想要的是java.lang.reflect.Proxy及其相关类提供的功能。


1
这需要一个接口存在,所以在这种情况下相当无用。 - Michael Borgwardt
1
我同意那是真的,但问题并不十分稳定。 - Pointy
我认为你把JDK代理机制和字节码操作库(如asm或cglib)混淆了。 - Sean Patrick Floyd
不一定是错误的;想一想。如果一个真实的方法在任何接口中都不存在,那么它有什么意义呢?你如何使用它以获得它是真正的静态类型方法的任何好处呢? - Stijn de Witt

4

这篇文章是一个很好的起点,但你确定需要创建一个新类吗?也许你可以只使用Map?


使用 CodeModel 缩小到我尚未创建的类是有问题的,这篇文章通过 Javassist 轻松解决了我的问题:ClassPool.getDefault().makeClass(clazzString).toClass(); - EGHM

1

正如@Bozho所说,Java是一种静态类型语言,运行时生成类只会导致混乱。

在我们的世界中,更方便的做法是在构建时生成类,也就是在编译期间。通常情况下,使用Hibernate反向工程,您可以从数据库模式构建Java类,并在应用程序中部署这些类,这样您就可以阅读到真实的Java代码,并保证您的代码将绑定到您的数据库模式。


1

这篇文章讲述了关于“新”的编译器API,以及JavaCompiler的Java文档展示了如何从String对象编译Java源代码。(我不知道是否可以将其编译为输出流并在内存中加载类文件...)

您可以使用URLClassLoader稍后加载类文件,并创建实例(反射/调用API)。


0

旧问题如果可能的话,应该避免在运行时生成类,但有时必须这样做。因此,您可以使用Javassist,以下是一个示例...

我在这里创建了一个小示例:http://hrabosch.com/2018/04/08/generate-class-during-runtime-with-javassist/

但这里是主要要点:

public static Class generateClass(String className, String methodName, String methodBody)
  throws CannotCompileException {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass(className);
StringBuffer method = new StringBuffer();
method.append("public void ")
      .append(methodName)
      .append("() {")
      .append(methodBody)
      .append(";}");
cc.addMethod(CtMethod.make(method.toString(), cc));
return cc.toClass();
}

所以我做了什么...通过Javassist,我在ClassPool中创建了一个类。同时,我在这个类中添加了一个方法,并通过反射调用它。
希望能有所帮助。
请记住,无论您想在生成的类中使用什么,都没有导入,因此您必须使用完全限定名称。

0

0

0

我想最终目标是拥有类似 ActiveRecord 的代码来编写数据库访问。如果是这种情况,您可以查看 Java 实现的 ActiveRecord: http://code.google.com/p/activejdbc/

祝好!

igor


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