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

  • 相关阅读:
    C++0x standard & features in VC10
    Win32 结构化异常处理(SEH)探秘
    What Every Programmer Should Know About Memory
    Memory leak detector(C++)
    NT's Asynchronous Procedure Call
    服务器应用程序不可用
    不安全代码只会在使用 /unsafe 编译的情况下出现
    关于“因为数据库正在使用,所以无法获得对数据库的独占访问权”的最终解决方案
    让 PowerDesigner 支持 SQLite!
    基于.Net的单点登录(SSO)解决方案
  • 原文地址:https://www.cnblogs.com/fanghao/p/10770924.html
Copyright © 2020-2023  润新知