读书人

java 利用反照模拟动态语言的 eval 函

发布时间: 2013-03-28 10:20:24 作者: rapoo

java 利用反射模拟动态语言的 eval 函数
package test.dynamic;import java.lang.reflect.Method;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);}}

?

?

package test.dynamic;import java.net.URI;import java.util.Arrays;import javax.tools.DiagnosticCollector;import javax.tools.JavaCompiler;import javax.tools.JavaFileObject;import javax.tools.SimpleJavaFileObject;import javax.tools.ToolProvider;public class MyClassLoader extends ClassLoader {@Overridepublic 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<String> 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;}}

?

?

?

下面是把源代码生成在磁盘上再加载到内存中的实现

?

package test.dynamic;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 Eval2 {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,创建URLClassLoaderURLClassLoader myClassLoader = new URLClassLoader(urls);// 加载Temp类(如果要加载内存中的class文件-二进制码,需要自己写类加载器)Class clazz = myClassLoader.loadClass("Temp");// 获取rt方法Method rt = clazz.getMethod("rt");// 动态调用rt方法return rt.invoke(clazz.newInstance());}}

?

读书人网 >编程

热点推荐