Java动态编译

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进程来外部编译。感觉这种注入代码的方式有一定的灵活性。

posted @ 2019-04-25 20:57  潇雨危栏  阅读(359)  评论(0编辑  收藏  举报