Java动态编译
最近熟悉了一下反射,对Java的动态性有了进一步的了解,因此想实现一下用Java直接动态生成.class文件,也就是在编译完成后,运行时编译java文件
工程结构
➜ helloworld tree
.
├── bin
│ └── helloworld
│ ├── Car.java
├── src
│ └── helloworld
│ ├── TestDynamicCompile.java
测试程序
TestDynamicCompile.java
package helloworld;
import java.net.MalformedURLException;
import java.util.Scanner;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
public class TestDynamicCompile {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, MalformedURLException {
Scanner scanner = new Scanner(System.in);
String className = "helloworld.Car";//scanner.next(); // "helloworld.Car"
scanner.close();
try {
Class.forName(className);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
System.out.println("Class not found");
System.out.println("dynamic compiling...");
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// 等同于javac 命令,生成的class文件默认在.java文件的同一个文件夹下
int flag = compiler.run(null, null, null, "bin/helloworld/Car.java");
System.out.println(flag==0? "编译成功" : "编译失败");
}
try {
Class<?> c = Class.forName(className);
Object obj = c.newInstance();
System.out.println(obj);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
将被动态编译的程序
Car.java(放在bin/helloworld目录下)
package helloworld;
public class Car {
private String name;
private int ID;
@Override
public String toString() {
return "name = " + name + " ID = " + ID;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getID() {
return ID;
}
public void setID(int ID) {
this.ID = ID;
}
public Car(){
this.name = "Default";
this.ID = 123;
}
}
编译TestDynamicCompile.java
➜ helloworld tree
.
├── bin
│ └── helloworld
│ ├── Car.java
│ └── TestDynamicCompile.class
├── src
│ └── helloworld
│ ├── TestDynamicCompile.java
可以看到Car还未被编译,TestDynamicCompile.class已经静态编译完成
运行后
➜ helloworld tree
.
├── bin
│ └── helloworld
│ ├── Car.class
│ ├── Car.java
│ └── TestDynamicCompile.class
├── src
│ └── helloworld
│ ├── TestDynamicCompile.java
可以看到Car.class字节文件在运行时被JavaCompiler编译出来
运行输出
Class not found
dynamic compiling...
编译成功
name = Default ID = 123
小结
Java实现了"自举",可以自己编译自己,而不用再起一个javac进程来外部编译。感觉这种注入代码的方式有一定的灵活性。