java反射机制以及应用

别来无恙 提交于 2019-11-27 12:58:55

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)clazz.getFields()  返回该对象的所有属性。

二、应用

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.模拟运行时异常,传入代码如下:

运行结果如下:

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!