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.代码:

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider; public class RunStudentPro {
private static String CLASSPATH;
/**
* 程序运行成功
*/
private static final boolean SUCCESS = true;
/**
* 程序运行失败
*/
private static final boolean DEFAULT = false; /**
* 编译期的错误列表
*/
private List<String> bianYiError; /**
* 学生运行的结果
*/
private Object studenResult; /**
* 运行时异常
*/
private List<String> runTimeErrors; /**
* 运行学生程序的主方法
*
* @param pro
* 学生代码
* @param javaName
* 学生类名
* @param methodName
* 学生方法
* @return
*/
public boolean runStudentProgram(String pro, String javaName, String methodName, String studentID) {
// 获取类所在的路径
CLASSPATH = this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath(); if (System.getProperty("os.name").contains("dows")) {
CLASSPATH = CLASSPATH.substring(1, CLASSPATH.length());
} if (CLASSPATH.endsWith(".jar")) {
CLASSPATH = CLASSPATH.substring(0, CLASSPATH.lastIndexOf("/") + 1);
} CLASSPATH = CLASSPATH + studentID + "/"; // 在本地写入java文件
writejavaFile(CLASSPATH, javaName, pro);
// 编译java文件
boolean javaCompilerFile = JavaCompilerFile(javaName); if (!javaCompilerFile) {
// 编译期失败
return DEFAULT;
} boolean runStudentProgram = runStudentProgram(javaName, methodName); if (!runStudentProgram) {
// 运行失败
return DEFAULT;
} return SUCCESS;
} /**
* 编译学生的java文件
*
* @param javaName
* @return
*/
private boolean JavaCompilerFile(String javaName) {
StandardJavaFileManager javafile = null;
boolean result = SUCCESS; try {
JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
javafile = javac.getStandardFileManager(null, null, null);
DiagnosticCollector<JavaFileObject> collector = new DiagnosticCollector<>();
String filename = CLASSPATH + javaName + ".java";
Iterable<? extends JavaFileObject> units = javafile.getJavaFileObjects(filename);
CompilationTask t = javac.getTask(null, javafile, collector, null, null, units); if (!t.call()) {
List<Diagnostic<? extends JavaFileObject>> diagnostics = collector.getDiagnostics();
bianYiError = new ArrayList<String>();
for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics) {
bianYiError.add(diagnostic.toString());
}
result = DEFAULT;
}
} finally {
try {
if (javafile != null) {
javafile.close();
}
} catch (IOException e) {
e.printStackTrace();
}
} return result;
} /**
* 运行学生的程序
*
* @param javaName
* 主类名
* @param methodName
* 方法名
* @return
*/
private boolean runStudentProgram(String javaName, String methodName) {
URLClassLoader classload = null;
boolean result = SUCCESS; try {
URL url = new URL("file:/" + CLASSPATH);
URL[] urls = new URL[] { url };
classload = new URLClassLoader(urls);
Class<?> clazz = classload.loadClass(javaName);
Method method = clazz.getMethod(methodName);
studenResult = method.invoke(clazz.newInstance());
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException | InstantiationException
| MalformedURLException e) {
runTimeErrors = new ArrayList<String>();
runTimeErrors.add(getExceptionAllinformation(e));
result = DEFAULT;
} finally {
if (classload != null) {
try {
classload.close();
} catch (IOException e) {
e.printStackTrace();
result = DEFAULT;
}
}
} return result;
} /**
* 获取异常的所有信息并转换为字符串
*
* @param ex
* @return
*/
private static String getExceptionAllinformation(Exception ex) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
PrintStream pout = new PrintStream(out);
ex.printStackTrace(pout);
String ret = new String(out.toByteArray());
pout.close();
try {
out.close();
} catch (Exception e) {
}
return ret;
} /**
* 创建java文件
*
* @param path
* 路径
* @param javaName
* 文件名
* @param pro
* 程序字符串
*/
private static void writejavaFile(String path, String javaName, String pro) {
File dir = new File(path); if (!dir.exists()) {
dir.mkdir();
} File file = new File(path + javaName + ".java"); if (file.exists()) {
file.delete();
}
FileWriter fw = null;
try {
file.createNewFile();
fw = new FileWriter(file);
fw.write(pro);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} /**
* 获取编译时的错误信息
*
* @return
*/
public List<String> getBianYiError() {
return bianYiError;
} /**
* 获取学生运行后的结果
*
* @return
*/
public Object getStudenResult() {
return studenResult;
} /**
* 获取学生运行时的异常
*
* @return
*/
public List<String> getRunTimeErrors() {
return runTimeErrors;
}
}

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. 推荐MarkDown编辑工具Typora--文本画流程图示例

    程序员界名言:talk is cheap, show me the code CODE: ### 8. 修改预留手机号-per.MCReservedMobilePhoneUpd #### 8.1业务规 ...

  2. tonight i need your body

    wdnmd wdnmd 再lable中我们有几个不同的type参数: text     写的是文本类型的参数 password    不管输入的是什么显示的都是星星 date    输入的是一个日历本 ...

  3. el-form-item内容过多,及弹窗框宽度属性show-overflow-tooltip设置

    内容过多: :show-overflow-tooltip=true 宽度属性设置: .el-tooltip__popper{ max-width:30% }

  4. stat - 打印信息节点(inode)内容

    SYNOPSIS(总览) stat filename [filenames ... ] DESCRIPTION(描述) stat 打印出一个信息节点的内容,它们显示为对人可读的格式的stat(2). ...

  5. 企业级NginxWeb服务优化实战(上)

    企业级NginxWeb服务优化实战(上) 1. Nginx基本安全优化 1.1 调整参数隐藏Nginx软件版本号信息 一般来说,软件的漏洞都和版本有关,这个很像汽车的缺陷,同一批次的要有问题就都有问题 ...

  6. 【TJOI/HEOI2016】求和

    题面 题目分析 \[ \begin{split} \sum_{i=0}^n\sum_{j=0}^iS(i,j)\cdot 2^j\cdot j!&=\sum_{j=0}^n2^j\cdot j ...

  7. vs code的简单插件

    Auto Close Tag VSCode Color Info Mithril Emmet support for VS Code Open HTML in Default Browser open ...

  8. 二维差分前缀和——cf1202D(好题)

    直接枚举每个点作为左上角是可以做的,但是写起来较麻烦 有一种较为简单的做法是对一列或一行统计贡献 比如某一行的B存在的区间是L,R那么就有三种情况 1.没有这样的区间,即一行都是W,此时这行对答案的贡 ...

  9. RichView

    TRichView中文文档 TRichView 是Delphi/C++Builder  控件,主要用于显示.编辑和打印超文本文档. 新版本解决多个兼容性问题,更新了字符串标签.剪贴板.RTF和DB组件 ...

  10. 20165239 2018——2019Exp8 Web基础

    Exp8 Web基础 基础问题回答 (1)什么是表单 •表单在网页中主要负责数据采集功能. •一个表单有三个基本组成部分: ◦表单标签,这里面包含了处理表单数据所用CGI程序的URL以及数据提交到服务 ...