博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java 利用反射模拟动态语言的 eval 函数
阅读量:6293 次
发布时间:2019-06-22

本文共 4759 字,大约阅读时间需要 15 分钟。

hot3.png

 

import java.io.File;import java.io.FileWriter;import java.io.PrintWriter;import java.lang.reflect.Method;import java.net.URL;import java.net.URLClassLoader;public class Eval {	public static Object eval(String str) throws Exception {		StringBuffer sb = new StringBuffer();		sb.append("public class Temp");		sb.append("{");		sb.append("    public Object getObject()");		sb.append("    {");		sb.append("        " + str + "return new Object();");		sb.append("    }");		sb.append("}");		// 调用自定义类加载器加载编译在内存中class文件		// 说明:这种方式也需要些数据落地写磁盘的		// 为毛一定要落地呢,直接内存里加载不就完了嘛		// 应该也是可以的,它从磁盘读了也是进内存		// 只不过java不允许直接操作内存		// 写jni估计是可以		Class clazz = new MyClassLoader().findClass(sb.toString());		Method method = clazz.getMethod("getObject");		// 通过反射调用方法		return method.invoke(clazz.newInstance());	}	public static void main(String[] args) throws Exception {		Object rval = eval("System.out.println(\"Hello World\");");		System.out.println(rval);	}}/*http://hi.baidu.com/rqzmvfodkxadine/item/a789f2117af5474ee65e0657http://blog.csdn.net/leeyohn/article/details/5179422http://www.99inf.net/SoftwareDev/Java/33737.htm*//*public class Eval{    public static void main(String[] args)throws Exception    {         Object rval = eval("System.out.println(\"Hello World\");return 5;");         System.out.println(rval);    }    public static Object eval(String str)throws Exception    {          //生成Java源文件          StringBuilder s = new StringBuilder("public class Temp{");          s.append("        public Object rt(){");          s.append("                " + str);          s.append("        }");          s.append("}");          //在当前目录生成Java源文件         File f = new File("Temp.java");          PrintWriter pw = new PrintWriter(new FileWriter(f));          pw.println(s.toString());          pw.close();          //动态编译(此处可直接编译内存中的Java源码,二进制码也放在内存中)         //使用这些动态编译的方式的时候,需要确保JDK中的tools.jar在应用的 CLASSPATH中。         com.sun.tools.javac.Main javac = new com.sun.tools.javac.Main();          // 这里eclipse寻找class的路径就是在bin下面找的, 需要把class编译到项目的 bin目录下         String[] cpargs = new String[] {"-d", "./bin" ,"Temp.java"};          //动态编译         int status = javac.compile(cpargs);          if(status != 0 )         {                  System.out.println("您给的Java代码有错!");                  return null;          }          //创建一个URL数组         URL[] urls = {new URL("file:Temp.class")};         //以默认的ClassLoader作为父ClassLoader,创建URLClassLoader         URLClassLoader myClassLoader = new URLClassLoader(urls);         //加载Temp类(如果要加载内存中的class文件-二进制码,需要自己写类加载器)         Class clazz = myClassLoader.loadClass("Temp");          //获取rt方法         Method rt = clazz.getMethod("rt");          //动态调用rt方法         return rt.invoke(clazz.newInstance());     } }*/

 

import java.util.Arrays;import javax.tools.JavaCompiler.CompilationTask;import javax.tools.SimpleJavaFileObject;import javax.tools.JavaFileObject;import javax.tools.JavaCompiler;import javax.tools.StandardJavaFileManager;import javax.tools.ToolProvider;import javax.tools.DiagnosticCollector;import java.net.URI;import java.net.URISyntaxException;public class MyClassLoader extends ClassLoader {	@Override	public Class
findClass(String str) throws ClassNotFoundException { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); // 用于诊断源代码编译错误的对象 DiagnosticCollector diagnostics = new DiagnosticCollector(); // 内存中的源代码保存在一个从JavaFileObject继承的类中 JavaFileObject file = new JavaSourceFromString("Temp", str.toString()); // System.out.println(file); Iterable compilationUnits = Arrays.asList(file); // 关于报:Exception in thread "main" java.lang.ClassNotFoundException: Temp // 的解决方法:http://willam2004.iteye.com/blog/1026454 // 需要为compiler.getTask方法指定编译路径: // 执行过程如下: // 1、定义类的字符串表示。 // 2、编译类 // 3、加载编译后的类 // 4、实例化并进行调用。 // 在eclipse下如果按照上述的方式进行调用,会在第三步中加载编译的类过程抛出“ClassNotFoundException”。 // 因为默认的Eclipse的java工程编译后的文件是放在当前工程下的bin目录下。而第二步编译输出的路径是工程目录下, // 所以加载时会抛出类找不到的错误。 String flag = "-d"; String outDir = System.getProperty("user.dir") + "/" + "bin"; Iterable
stringdir = Arrays.asList(flag, outDir); // 指定-d dir 参数 // 建立一个编译任务 JavaCompiler.CompilationTask task = compiler.getTask(null, null, null, stringdir, null, compilationUnits); // 编译源程序 boolean result = task.call(); if (result) { return Class.forName("Temp"); } return null; }}class JavaSourceFromString extends SimpleJavaFileObject { private String name; private String code; public JavaSourceFromString(String name, String code) { super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); this.code = code; } public CharSequence getCharContent(boolean ignoreEncodingErrors) { return code; }}

 

Refer:

[1] Java 类的热替换 —— 概念、设计与实现

转载于:https://my.oschina.net/leejun2005/blog/81729

你可能感兴趣的文章
sbin/hadoop-daemon.sh: line 165: /tmp/hadoop-hxsyl-journalnode.pid: Permission denied
查看>>
@RequestMapping 用法详解之地址映射
查看>>
254页PPT!这是一份写给NLP研究者的编程指南
查看>>
《Data Warehouse in Action》
查看>>
String 源码浅析(一)
查看>>
Spring Boot 最佳实践(三)模板引擎FreeMarker集成
查看>>
Fescar 发布 0.2.3 版本,支持 Redis 和 Apollo
查看>>
Google MapReduce到底解决什么问题?
查看>>
CCNP-6 OSPF试验2(BSCI)
查看>>
Excel 2013 全新的图表体验
查看>>
openstack 制作大于2TB根分区自动扩容的CENTOS镜像
查看>>
Unbuntu安装遭遇 vmware上的Easy install模式
查看>>
几个常用的ASP木马
查看>>
python分析postfix邮件日志的状态
查看>>
Mysql-5.6.x多实例配置
查看>>
psutil
查看>>
在git@osc上托管自己的代码
查看>>
机器学习算法:朴素贝叶斯
查看>>
小五思科技术学习笔记之扩展访问列表
查看>>
使用Python脚本检验文件系统数据完整性
查看>>