JAVA反射机制+动态运行编译期不存在的JAVA程序

一、有关JAVA反射

在运行期间,在不知道某个类A的内部方法和属性时,能够动态的获取信息、获取类或对象的方法、属性的功能,称之为反射。

1.相关类:

(1)Class

(2)Method

(3)Field

2.相关方法:

(1)Class.forName("<完整包名+类名>");  返回对应的类(同一JVM不管创建该类的多少对象,类只有一个)。

(2)class.getMethod(要获取的方法名,参数类型,参数类型.....);  返回该方法。

(3)执行方法method.invoke(实例,参数,参数.....)  返回该方法的返回值(Object类型,可强转为指定类型)。

(4)class.newInstance()  返回一个实例对象,通常与(3)一起使用。

(5)class.getFields()  返回该对象的所有共有属性。

(6)class.getDeclaredFields  获取对象的共有+私有属性。

二、应用

1.简介:

公司有个项目,需要将提交上来的Java源码进行编译与运行,并返回结果。一般的思想是JVM-命令行-JVM的模式。但是这样不但执行速度慢,且获取编译异常、运行异常、运行结果都是非常困难的。所以通过JAVA反射机制,以及自带的编译工具完成功能。

2.代码:

  1. import java.io.ByteArrayOutputStream;
  2. import java.io.File;
  3. import java.io.FileWriter;
  4. import java.io.IOException;
  5. import java.io.PrintStream;
  6. import java.lang.reflect.InvocationTargetException;
  7. import java.lang.reflect.Method;
  8. import java.net.MalformedURLException;
  9. import java.net.URL;
  10. import java.net.URLClassLoader;
  11. import java.util.ArrayList;
  12. import java.util.List;
  13. import javax.tools.Diagnostic;
  14. import javax.tools.DiagnosticCollector;
  15. import javax.tools.JavaCompiler;
  16. import javax.tools.JavaCompiler.CompilationTask;
  17. import javax.tools.JavaFileObject;
  18. import javax.tools.StandardJavaFileManager;
  19. import javax.tools.ToolProvider;
  20.  
  21. public class RunStudentPro {
  22. private static String CLASSPATH;
  23. /**
  24. * 程序运行成功
  25. */
  26. private static final boolean SUCCESS = true;
  27. /**
  28. * 程序运行失败
  29. */
  30. private static final boolean DEFAULT = false;
  31.  
  32. /**
  33. * 编译期的错误列表
  34. */
  35. private List<String> bianYiError;
  36.  
  37. /**
  38. * 学生运行的结果
  39. */
  40. private Object studenResult;
  41.  
  42. /**
  43. * 运行时异常
  44. */
  45. private List<String> runTimeErrors;
  46.  
  47. /**
  48. * 运行学生程序的主方法
  49. *
  50. * @param pro
  51. * 学生代码
  52. * @param javaName
  53. * 学生类名
  54. * @param methodName
  55. * 学生方法
  56. * @return
  57. */
  58. public boolean runStudentProgram(String pro, String javaName, String methodName, String studentID) {
  59. // 获取类所在的路径
  60. CLASSPATH = this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
  61.  
  62. if (System.getProperty("os.name").contains("dows")) {
  63. CLASSPATH = CLASSPATH.substring(1, CLASSPATH.length());
  64. }
  65.  
  66. if (CLASSPATH.endsWith(".jar")) {
  67. CLASSPATH = CLASSPATH.substring(0, CLASSPATH.lastIndexOf("/") + 1);
  68. }
  69.  
  70. CLASSPATH = CLASSPATH + studentID + "/";
  71.  
  72. // 在本地写入java文件
  73. writejavaFile(CLASSPATH, javaName, pro);
  74. // 编译java文件
  75. boolean javaCompilerFile = JavaCompilerFile(javaName);
  76.  
  77. if (!javaCompilerFile) {
  78. // 编译期失败
  79. return DEFAULT;
  80. }
  81.  
  82. boolean runStudentProgram = runStudentProgram(javaName, methodName);
  83.  
  84. if (!runStudentProgram) {
  85. // 运行失败
  86. return DEFAULT;
  87. }
  88.  
  89. return SUCCESS;
  90. }
  91.  
  92. /**
  93. * 编译学生的java文件
  94. *
  95. * @param javaName
  96. * @return
  97. */
  98. private boolean JavaCompilerFile(String javaName) {
  99. StandardJavaFileManager javafile = null;
  100. boolean result = SUCCESS;
  101.  
  102. try {
  103. JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
  104. javafile = javac.getStandardFileManager(null, null, null);
  105. DiagnosticCollector<JavaFileObject> collector = new DiagnosticCollector<>();
  106. String filename = CLASSPATH + javaName + ".java";
  107. Iterable<? extends JavaFileObject> units = javafile.getJavaFileObjects(filename);
  108. CompilationTask t = javac.getTask(null, javafile, collector, null, null, units);
  109.  
  110. if (!t.call()) {
  111. List<Diagnostic<? extends JavaFileObject>> diagnostics = collector.getDiagnostics();
  112. bianYiError = new ArrayList<String>();
  113. for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics) {
  114. bianYiError.add(diagnostic.toString());
  115. }
  116. result = DEFAULT;
  117. }
  118. } finally {
  119. try {
  120. if (javafile != null) {
  121. javafile.close();
  122. }
  123. } catch (IOException e) {
  124. e.printStackTrace();
  125. }
  126. }
  127.  
  128. return result;
  129. }
  130.  
  131. /**
  132. * 运行学生的程序
  133. *
  134. * @param javaName
  135. * 主类名
  136. * @param methodName
  137. * 方法名
  138. * @return
  139. */
  140. private boolean runStudentProgram(String javaName, String methodName) {
  141. URLClassLoader classload = null;
  142. boolean result = SUCCESS;
  143.  
  144. try {
  145. URL url = new URL("file:/" + CLASSPATH);
  146. URL[] urls = new URL[] { url };
  147. classload = new URLClassLoader(urls);
  148. Class<?> clazz = classload.loadClass(javaName);
  149. Method method = clazz.getMethod(methodName);
  150. studenResult = method.invoke(clazz.newInstance());
  151. } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException
  152. | IllegalArgumentException | InvocationTargetException | InstantiationException
  153. | MalformedURLException e) {
  154. runTimeErrors = new ArrayList<String>();
  155. runTimeErrors.add(getExceptionAllinformation(e));
  156. result = DEFAULT;
  157. } finally {
  158. if (classload != null) {
  159. try {
  160. classload.close();
  161. } catch (IOException e) {
  162. e.printStackTrace();
  163. result = DEFAULT;
  164. }
  165. }
  166. }
  167.  
  168. return result;
  169. }
  170.  
  171. /**
  172. * 获取异常的所有信息并转换为字符串
  173. *
  174. * @param ex
  175. * @return
  176. */
  177. private static String getExceptionAllinformation(Exception ex) {
  178. ByteArrayOutputStream out = new ByteArrayOutputStream();
  179. PrintStream pout = new PrintStream(out);
  180. ex.printStackTrace(pout);
  181. String ret = new String(out.toByteArray());
  182. pout.close();
  183. try {
  184. out.close();
  185. } catch (Exception e) {
  186. }
  187. return ret;
  188. }
  189.  
  190. /**
  191. * 创建java文件
  192. *
  193. * @param path
  194. * 路径
  195. * @param javaName
  196. * 文件名
  197. * @param pro
  198. * 程序字符串
  199. */
  200. private static void writejavaFile(String path, String javaName, String pro) {
  201. File dir = new File(path);
  202.  
  203. if (!dir.exists()) {
  204. dir.mkdir();
  205. }
  206.  
  207. File file = new File(path + javaName + ".java");
  208.  
  209. if (file.exists()) {
  210. file.delete();
  211. }
  212. FileWriter fw = null;
  213. try {
  214. file.createNewFile();
  215. fw = new FileWriter(file);
  216. fw.write(pro);
  217. } catch (IOException e) {
  218. e.printStackTrace();
  219. } finally {
  220. try {
  221. fw.close();
  222. } catch (IOException e) {
  223. e.printStackTrace();
  224. }
  225. }
  226. }
  227.  
  228. /**
  229. * 获取编译时的错误信息
  230. *
  231. * @return
  232. */
  233. public List<String> getBianYiError() {
  234. return bianYiError;
  235. }
  236.  
  237. /**
  238. * 获取学生运行后的结果
  239. *
  240. * @return
  241. */
  242. public Object getStudenResult() {
  243. return studenResult;
  244. }
  245.  
  246. /**
  247. * 获取学生运行时的异常
  248. *
  249. * @return
  250. */
  251. public List<String> getRunTimeErrors() {
  252. return runTimeErrors;
  253. }
  254. }

3.详细讲解:

(1)程序入口为public boolean runStudentProgram(String pro, String javaName, String methodName, String studentID)

通过传入代码、主类名称、要执行的方法名、学生ID,进行保存代码,编译代码、运行代码。

其中,this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath()获取当前类所在的目录(主要是方便移植,此路径可写死或修改为指定目录),然后将.jar及开头的'/'符号去除。

(2)编译学生代码:

通过JavaCompiler类进行编译(JDK1.6提供),使用方式为JavaCompiler javac = ToolProvider.getSystemJavaCompiler();

注意的是,编译器接口是在javax.tools包里,所以可能IDE所配置的JRE不存在此类,所以报错的话直接更改JRE。

可以通过CompilationTask t = javac.getTask(null, javafile, collector, null, null, units);中设置collector获取编译的错误信息。

其中编译方法的运行为call()方法,也可以javac.run();

(3)运行学生代码:

method.invoke(clazz.newInstance());因为我们规定了不允许传入参数,所以此处只是传入了实例,并没有传入参数。

运行时的错误信息,可以通过异常Exception指定输出流进行保存。本程序的getExceptionAllinformation方法即为实现方法。

三、运行效果截图

1.正常运行,传入的代码如下

运行结果如下:

2.模拟编译时异常,传入代码如下:

运行结果如下:

3.模拟运行时异常,传入代码如下:

运行结果如下:

java反射机制以及应用的更多相关文章

  1. 第28章 java反射机制

    java反射机制 1.类加载机制 1.1.jvm和类 运行Java程序:java 带有main方法的类名 之后java会启动jvm,并加载字节码(字节码就是一个类在内存空间的状态) 当调用java命令 ...

  2. Java反射机制

    Java反射机制 一:什么事反射机制 简单地说,就是程序运行时能够通过反射的到类的所有信息,只需要获得类名,方法名,属性名. 二:为什么要用反射:     静态编译:在编译时确定类型,绑定对象,即通过 ...

  3. java基础知识(十一)java反射机制(上)

    java.lang.Class类详解 java Class类详解 一.class类 Class类是java语言定义的特定类的实现,在java中每个类都有一个相应的Class对象,以便java程序运行时 ...

  4. java基础知识(十一)java反射机制(下)

    1.什么是反射机制? java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象都能够调用他的属性和方法,这种动态获取属性和方法的功能称为java的反射机制. ...

  5. Java反射机制专题

    ·Java Reflection Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方 ...

  6. java反射机制深入详解

    java反射机制深入详解  转自:http://www.cnblogs.com/hxsyl/archive/2013/03/23/2977593.html 一.概念 反射就是把Java的各种成分映射成 ...

  7. Java反射机制DOME

    Java反射机制 public class TestHibernate { @Test public void TestHb(){ try { Class cs = Class.forName(&qu ...

  8. 反射——Java反射机制

    反射概述 什么是反射? ①   反射的概念是由Smith在1982年首次提出的,主要指程序可以访问.检测和修改它本身状态或行为的一种能力. ②   JAVA反射机制是在运行状态中,对应任意一个类,都能 ...

  9. Java反射机制可以动态修改实例中final修饰的成员变量吗?

    问题:Java反射机制可以动态修改实例中final修饰的成员变量吗? 回答是分两种情况的. 1. 当final修饰的成员变量在定义的时候就初始化了值,那么java反射机制就已经不能动态修改它的值了. ...

  10. Java反射机制学习与研究

    Java反射机制:可以获取正在运行时的Java对象. 1.判断运行时对象对象所属的类. 2.判断运行时对象所具有的成员变量和方法. 3.还可以调用到private方法,改变private变量的值. S ...

随机推荐

  1. zookeeper和dubbo可视化软件的使用

    1. zookeeper的可视化软件使用 Zkui 1. 下载软件 https://github.com/DeemOpen/zkui.git 2. 解压编译  clean install 会在targ ...

  2. tire 树入门

    博客: 模板: 前缀是否出现: /* trie tree的储存方式:将字母储存在边上,边的节点连接与它相连的字母 trie[rt][x]=tot:rt是上个节点编号,x是字母,tot是下个节点编号 * ...

  3. oracle锁表和解锁

    1.查看锁表清空 select * from v$session t1, v$locked_object t2 where t1.sid = t2.SESSION_ID; alter system k ...

  4. nexus私服仓库搭建以及项目引用

    第一步:使用ubunto下载安装nexus  并打开登录进入到nexus管理页面,默认账号为 admin  密码在 admin.password 中,首次登录会让你重新修改密码 第二步  配置自己本地 ...

  5. Codeforces 631E 斜率优化

    题意:给你一个数组,你可以选择数组中的一个数,把它插入数组的其它位置,问∑ i * a[i]的最大值为多少? 思路:设dp[i]表示把第i个数向左边插入可以获得的最大增量,我们假设向左边插入,设插入的 ...

  6. std::wcout输出1遍不输出

    std::wcout输出1遍不输出 程序明明在执行地方执行 wcout无法输出到控制台 cout就可以 添加中文支持即可

  7. 让APK只包含指定的ABI(转)

    转自:http://blog.csdn.net/justfwd/article/details/49308199 现在很多android第三方 sdk是以aar形式提供的,甚至是远程aar,如果这个s ...

  8. Map集合类(二.其他map集合jdk1.8)

    java集合笔记一 java集合笔记二 java集合笔记三 1.hashtable(线程安全) 1.存储数据为数组+链表2.存储键值对或获取时通过hash值取模数组长度确定节点在数组中的下标位置 in ...

  9. 二叉堆 与 PriorityQueue

    堆在存储器中的表示是数组,堆只是一个概念上的表示.堆的同一节点的左右子节点都没有规律. 堆适合优先级队列(默认排列顺序是升序排列,快速插入与删除最大/最小值). 数组与堆 堆(完全二叉树)(构造大顶堆 ...

  10. 赋能时空云计算,阿里云数据库时空引擎Ganos上线

    随着移动互联网.位置感知技术.对地观测技术的快速发展,时空信息已从传统GIS行业渗透到大众应用及各行各业.从静态POI(兴趣点)到APP位置信息,从导航电子地图到车辆行驶轨迹,从卫星影像到三维城市建模 ...