欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java编程思想-动态编译

程序员文章站 2022-07-13 15:46:22
...

 

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

 

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,编译之后可能产生安全隐患。