Java 是否有一种动态创建类(而不是实例)的方法?

Java 是否有一种动态创建类(而不是实例)的方法?,java,Java,我有一个关于如何动态创建类(而不是实例)的问题。 在我的项目中,我需要根据配置文件编写几个类似的类。 对于exmaple,有如下JSON: {

我有一个关于如何动态创建类(而不是实例)的问题。 在我的项目中,我需要根据配置文件编写几个类似的类。 对于exmaple,有如下JSON:

{                                                                                                                                                                              
    {                                                                                                                                                                          
        "lang": "python",                                                                                                                                                      
        "file": "class1.py",
        "args": ["arg1"]                                                                                                                                  
    },                                                                                                                                                                         
    {                                                                                                                                                                          
        "lang": "python",                                                                                                                                                      
        "file": "class2.py"  
        "args": ["arg2"]                                                                                                                                               
    }                                                                                                                                                                          
} 
随后,我需要编写以下两个java类:

类别1:

public class Class1 extends ShellBolt implements IRichBolt {
    public Class1() {
        super("python", "class1.py");
    }

    @Override
    public void declareOutputFields(OutputFieldsDeclarer declarer) {
        declarer.declare(new Fields(arg1));
    }

    @Override
    public Map<String, Object> getComponentConfiguration() {
        return null;
    }
}
我需要编写一个具有类似结构的新类。 那么,有没有一种动态创建类的方法? 我知道cglib可能有用,但我不知道如何在我的案例中使用它。 谢谢。

您可以使用将任何java代码编译为类文件。然后,您可以使用

javadocs中给出了一个示例,或者您可以查看完整的示例

应用于您的
Class1
,它看起来像下面的示例。请注意,您需要在代码中包含所有相关导入,否则它将无法编译

public static void main(String[] args) throws Exception {
    String packageName = "some.packagename";
    String className = packageName + ".Class1";
    String body = "package " + packageName + ";   " +
                "public class Class1 extends ShellBolt implements IRichBolt {\n" +
                "    public Class1() {\n" +
                "        super(\"python\", \"class1.py\");\n" +
                "    }\n" +
                "\n" +
                "    @Override\n" +
                "    public void declareOutputFields(OutputFieldsDeclarer declarer) {\n" +
                "        declarer.declare(new Fields(arg1));\n" +
                "    }\n" +
                "\n" +
                "    @Override\n" +
                "    public Map<String, Object> getComponentConfiguration() {\n" +
                "        return null;\n" +
                "    }\n" +
                "}";

    Path classFile = Paths.get(System.getProperty("user.home"));
    compile(className, body, classFile);
    Class<?> class1 = loadClass(className, classFile);

    Method getComponentConfiguration = class1.getDeclaredMethod("getComponentConfiguration");
    Map<String, Object> result = (Map<String, Object>) getComponentConfiguration.invoke(class1.newInstance());
}

private static Class<?> loadClass(String className, Path path) throws Exception {
    URLClassLoader loader = new URLClassLoader(new URL[]{path.toUri().toURL()}, Test1.class.getClassLoader());
    return loader.loadClass(className);
}

private static void compile(String className, String body, Path path) throws Exception {
    List<JavaSourceFromString> sourceCode = Arrays.asList(new JavaSourceFromString(className, body));

    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
    fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(path.toFile()));
    boolean ok = compiler.getTask(null, fileManager, null, null, null, sourceCode).call();

    System.out.println("compilation ok = " + ok);
}

public static class JavaSourceFromString extends SimpleJavaFileObject {
    final String code;

    JavaSourceFromString(String name, String code) {
        super(URI.create("string:///" + name.replace('.', '/') + JavaFileObject.Kind.SOURCE.extension),
                JavaFileObject.Kind.SOURCE);
        this.code = code;
    }

    @Override
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
        return code;
    }
}
publicstaticvoidmain(字符串[]args)引发异常{
String packageName=“some.packageName”;
字符串className=packageName+“.Class1”;
String body=“package”+packageName+”+
“公共类Class1扩展ShellBolt实现IRichBolt{\n”+
“公共类1(){\n”+
超级(\'python\',\'class1.py\');\n+
“}\n”+
“\n”+
“@覆盖\n”+
“public void declareOutputFields(outputfieldsclarer declarer){\n”+
“declarer.declare(新字段(arg1));\n”+
“}\n”+
“\n”+
“@覆盖\n”+
“公共映射getComponentConfiguration(){\n”+
“返回空值;\n”+
“}\n”+
"}";
Path classFile=Path.get(System.getProperty(“user.home”);
编译(类名、主体、类文件);
Class class1=loadClass(类名,类文件);
方法getComponentConfiguration=class1.getDeclaredMethod(“getComponentConfiguration”);
Map result=(Map)getComponentConfiguration.invoke(class1.newInstance());
}
私有静态类loadClass(字符串类名,路径路径)引发异常{
URLClassLoader=newURLClassLoader(新URL[]{path.toUri().toURL()},Test1.class.getClassLoader());
返回loader.loadClass(类名);
}
私有静态void编译(字符串类名、字符串体、路径路径)引发异常{
List sourceCode=Arrays.asList(新的JavaSourceFromString(className,body));
JavaCompiler=ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager=compiler.getStandardFileManager(null,null,null);
setLocation(StandardLocation.CLASS_输出,Arrays.asList(path.toFile());
boolean ok=compiler.getTask(null,fileManager,null,null,null,sourceCode).call();
System.out.println(“编译ok=“+ok”);
}
公共静态类JavaSourceFromString扩展了SimpleJavaFileObject{
最终字符串代码;
JavaSourceFromString(字符串名称、字符串代码){
super(URI.create(“string://“+name.replace('.','/'))+JavaFileObject.Kind.SOURCE.extension),
JavaFileObject.Kind.SOURCE);
this.code=代码;
}
@凌驾
public CharSequence getCharContent(布尔ignoreEncodingErrors){
返回码;
}
}
< /代码> 如果您确实需要动态创建JVM中的类,请考虑使用诸如Groovy之类的动态语言。

另一种方法:如果您需要解释JVM上的一些Python代码,请考虑使用Jython。


在HotSpot JVM中动态创建类存在危险。如果创建的动态类太多,可能会耗尽PermGen空间,JVM将崩溃,出现
OutOfMemory
错误。但是,还有一些解决方法,例如通过
-XX:+useConMarkSweepGC-XX:+CMSClassUnloadingEnabled-XX:+CMSPermGenSweepingEnabled
jvm参数为PermGen启用垃圾收集。宣布将在JVM 8中删除PermGen。

是的,有一种方法。您应该创建自己的实现,重写它的
loadClass
方法,然后调用
defineClass
,为它提供字节码。没有生成字节码的内置类,但您始终可以使用。然后实例化
ClassLoader
,从中获取类:

ClassLoader myClassLoader = new MyClassLoader(ClassLoader.getSystemClassLoader());
Class<?> generatedClass = Class.forName("pkg.GeneratedClass", true, myClassLoader);
Object instance = generatedClass.newInstance();

为什么需要创建这些类?为什么仅仅有一个类来封装配置文件中的JSON对象并具有根据该对象的内容行为的方法就不够了?有这样的库允许您在运行时创建类这是一篇讨论类似问题的文章:@Philipp hi Philipp,我知道有人可能有这个问题。但不幸的是,我在这里使用的框架只需要像这样。类似类的实例将在稍后使用。
public static void main(String[] args) throws Exception {
    String packageName = "some.packagename";
    String className = packageName + ".Class1";
    String body = "package " + packageName + ";   " +
                "public class Class1 extends ShellBolt implements IRichBolt {\n" +
                "    public Class1() {\n" +
                "        super(\"python\", \"class1.py\");\n" +
                "    }\n" +
                "\n" +
                "    @Override\n" +
                "    public void declareOutputFields(OutputFieldsDeclarer declarer) {\n" +
                "        declarer.declare(new Fields(arg1));\n" +
                "    }\n" +
                "\n" +
                "    @Override\n" +
                "    public Map<String, Object> getComponentConfiguration() {\n" +
                "        return null;\n" +
                "    }\n" +
                "}";

    Path classFile = Paths.get(System.getProperty("user.home"));
    compile(className, body, classFile);
    Class<?> class1 = loadClass(className, classFile);

    Method getComponentConfiguration = class1.getDeclaredMethod("getComponentConfiguration");
    Map<String, Object> result = (Map<String, Object>) getComponentConfiguration.invoke(class1.newInstance());
}

private static Class<?> loadClass(String className, Path path) throws Exception {
    URLClassLoader loader = new URLClassLoader(new URL[]{path.toUri().toURL()}, Test1.class.getClassLoader());
    return loader.loadClass(className);
}

private static void compile(String className, String body, Path path) throws Exception {
    List<JavaSourceFromString> sourceCode = Arrays.asList(new JavaSourceFromString(className, body));

    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
    fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(path.toFile()));
    boolean ok = compiler.getTask(null, fileManager, null, null, null, sourceCode).call();

    System.out.println("compilation ok = " + ok);
}

public static class JavaSourceFromString extends SimpleJavaFileObject {
    final String code;

    JavaSourceFromString(String name, String code) {
        super(URI.create("string:///" + name.replace('.', '/') + JavaFileObject.Kind.SOURCE.extension),
                JavaFileObject.Kind.SOURCE);
        this.code = code;
    }

    @Override
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
        return code;
    }
}
ClassLoader myClassLoader = new MyClassLoader(ClassLoader.getSystemClassLoader());
Class<?> generatedClass = Class.forName("pkg.GeneratedClass", true, myClassLoader);
Object instance = generatedClass.newInstance();
@Override public void loadClass(String name) {
    if (name.equals("pkg.GeneratedClass")) {
        ClassWriter cw = new ClassWriter(0);
        cw.visit(V1_6, ACC_PUBLIC, "pkg/GeneratedClass", null, "java/lang/Object", null);
        // and so on, use ASM API to complete class generation,
        // see asm documentation
        byte[] bytecode = cw.toByteArray();
        return defineClass(name, bytecode, 0, bytecode.length);
    } else {
        return super.loadClass(name);
    }
}