想要在运行时动态拼接出一个类的代码,然后编译后创建对象,java动态编译可以吗,能提供一个简单的例子吗。或者用其他完全兼容java的jvm上的语言来编译然后创建对象也可以,我只搜到了用groovy的方式,但是好像不是完全兼容java语法的,我发现用java语法声明的数组,用groovy就没法编译。
2003 年由 Apache 推出的轻量级动态语言,吸收了 Python、Ruby 和 Smalltalk 语言的优秀特性,语法简洁,可有效提升开发效率。与 Java 完全互融,可互调对方支持库,由ASM生成普通的java字节码文件后通过JVM执行
class Fuck{
static void main(String[] args){
println "Hello,World!!!";
}
}
官网:https://www.groovy-lang.org/
答案:
Java支持动态编译,可以使用Java程序来实现。下面是一个简单的例子,展示如何在Java中使用动态编译来创建对象。
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;
public class DynamicCompile {
private static String className = "DynamicObj";
private static String packageName = "package com.example;";
private static String code;
static {
StringBuilder sb = new StringBuilder();
sb.append(packageName);
sb.append(" public class " + className + " {\n");
sb.append(" public int i;\n");
sb.append(" public int j;\n");
sb.append(" public " + className + "(int i, int j) {\n");
sb.append(" this.i = i;\n");
sb.append(" this.j = j;\n");
sb.append(" }\n");
sb.append(" public int add() {\n");
sb.append(" return this.i + this.j;\n");
sb.append(" }\n");
sb.append(" }");
code = sb.toString();
}
public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
// 获取编译器
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// 文件管理器
DynamicClassLoader classLoader = new DynamicClassLoader(DynamicCompile.class.getClassLoader());
// 内存中的源代码文件
List<JavaFileObject> sources = new ArrayList<>();
sources.add(new StringSourceFileObject(className, code));
// 编译任务
JavaCompiler.CompilationTask task = compiler.getTask(null, null, null, null, null, sources);
// 执行编译任务
if (task.call()) {
// 加载Class文件
Class<?> clazz = classLoader.loadClass(packageName + className);
// 创建对象
Object obj = clazz.getDeclaredConstructor(int.class, int.class).newInstance(1, 2);
// 调用方法
Method method = clazz.getDeclaredMethod("add");
int result = (int) method.invoke(obj);
System.out.println(result);
}
}
/**
* 内存中的源代码文件
*/
private static class StringSourceFileObject extends SimpleJavaFileObject {
private String code;
/**
* 构造方法
*
* @param className 类名
* @param code 源代码
*/
protected StringSourceFileObject(String className, String code) {
super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
this.code = code;
}
/**
* 返回源代码
*/
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return code;
}
}
/**
* 自定义ClassLoader,从指定的ClassPath中查找类
*/
private static class DynamicClassLoader extends ClassLoader {
private static final String CLASS_SUFFIX = ".class";
private String classPath;
/**
* 构造方法
*
* @param parent 父ClassLoader
*/
protected DynamicClassLoader(ClassLoader parent) {
super(parent);
classPath = System.getProperty("java.class.path");
}
/**
* 查找指定的类
*/
@Override
public Class<?> findClass(String name) throws ClassNotFoundException {
// 查找ClassPath上对应的类文件
String fileName = name.replace('.', '/') + CLASS_SUFFIX;
File file = new File(classPath, fileName);
if (file.exists()) {
try (FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int len = -1;
while ((len = fis.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
byte[] bytes = baos.toByteArray();
// 重新定义类
return defineClass(name, bytes, 0, bytes.length);
} catch (IOException e) {
e.printStackTrace();
}
}
return super.findClass(name);
}
}
}
此外,还可以使用其他语言来编译生成Java类文件,比如Groovy。下面是一个使用Groovy的例子,展示如何在Groovy中使用Java语法来动态编译生成Java类文件,并在Java中创建对象。
class DynamicObj {
int i
int j
DynamicObj(int i, int j) {
this.i = i
this.j = j
}
int add() {
return this.i + this.j
}
}
// 编译groovy代码生成class文件
import groovy.lang.GroovyClassLoader
import java.io.File
String code = """package com.example;
|class DynamicObj {
| int i
| int j
| DynamicObj(int i, int j) {
| this.i = i
| this.j = j
| }
| int add() {
| return this.i + this.j
| }
|}""".stripMargin() // groovy代码,使用Java语法
GroovyClassLoader loader = new GroovyClassLoader()
Class clazz = loader.parseClass(code)
File file = loader.getBytecode(clazz).file
println(file) // class文件所在路径
// 创建对象
ClassLoader parent = null // 父ClassLoader,一般为null即可
DynamicClassLoader classLoader = new DynamicClassLoader(parent)
Class<?> clazz = classLoader.loadClass("com.example.DynamicObj")
Object obj = clazz.getDeclaredConstructor(int.class, int.class).newInstance(1, 2)
Method method = clazz.getDeclaredMethod("add")
int result = (int) method.invoke(obj)
println(result)
以上代码展示了如何使用Groovy动态编译生成Java类文件,并在Java中使用ClassLoader加载,创建对象并调用方法。注意,在使用Groovy时需要引入相应的依赖包。
编译过后创建对象,你在其他没编译的地方也用不了,是要做什么功能呢?