java编程思想-动态编译

 

一般,我们用反射是可以在运行时洞悉一个类的信息(无论公私有),但是我们也可以在运行时创建一个新的类(原先不存在),然后加载该类,并调用该类中的函数。

 

1.创建一个类

这里我简便的用IO流将一个已经完成的类(与当前工程不再一个目录下),拷贝到当前工程目录下,当然也可以在运行时直接用字符串拼接处一个类,写入文件。

 

@SuppressWarnings("resource")
public static void copyClass() throws IOException{
File file = new File("src/com/annotation/AnnotationDemo.java");
FileChannel in = new FileInputStream("/Users/admin/Desktop/Hello.java").getChannel();
FileChannel out = new FileOutputStream("src/com/annotation/Hello.java").getChannel();
ByteBuffer buff = ByteBuffer.allocate(1024);
while(in.read(buff) != -1){
buff.flip();
out.write(buff);
buff.clear();
}
out.close();
in.close();

}

 

2.加载该类

由于我们创建好的类(文件)是.java,且该文件相当于是一种非正常途径建立的,所以并没有被编译过,所以要进行编译产生.class文件。

但是这里不能使用:

RunTime run = RunTime.getRunTime();

run.exec(command); //command = javac classname.java

因为他不会被执行

所以这里要使用专门的类编译工具,由JDK直接提供。

 

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
Iterable units = fileMgr.getJavaFileObjects("src/com/annotation/Hello.java");
CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
t.call();
fileMgr.close();

 

还有一点要注意的是,编译后的类直接在.java文件的同级目录下(当然也可以设置成将编译后产生的.class文件让入相应的位置),一般我们用eclipes的话 .class文件放在bin文件下,.java文件放在.src文件下的,所以我在这里做一个文件挪动的工作:

 

Runtime run = Runtime.getRuntime();
  run.exec("mv 目标.class当前路径 "+ "该.class应该被存放的路径");

 

 

3.反射调用

Class c = Class.forName("com.annotation.Hello");
Object o = c.newInstance();
Method m = c.getMethod("hello");
m.invoke(o);
System.out.println(c.getName());

 

因为类已经加载好了,所以我们就可以使用它的,当然是用反射的方式来调用,这种情况下,与一般的反射并没有区别了。

 

4.输出结果

helloworld

 

com.annotation.Hello

 

5.总结

 

其实这个例子意义并不大,只是感觉这应该是个比较偏门的东西,就拿出来分享一下,java并非在运行时不能创建类,相反的,java在运行时可以创建一个类,其实本质就相当于创建一个文件,但是重要的是如何要这个类被编译,这里只能使用javax提供的显示的类编译工具,一旦编译完成,产生.class文件后,之后的操作就一样了。

我想到的用途:

实现一个在线编译功能。(这样的话就变成调用另一个类的main方法。)

热部署(不停机替换文件)

 

缺点:

其实静态编译就已经能够完成绝大部分功能,并没有很大的需求使用动态编译

动态编译在框架中使用需要比较谨慎,比如在spring中动态编译一个类并把他加入到bean容器中是非常麻烦的

有其他更好的无缝脚本来支持动态编译,比如Groovy.

毕竟是一个编译过程,还是比较费时的

会产生注入漏洞,万一源代码来源有恶意BUG,编译之后可能产生安全隐患。

猜你喜欢

转载自870604904.iteye.com/blog/2273472
今日推荐