简单java在线测评程序

简单java程序在线测评程序

一.前言

  大家过年好!今年的第一篇博客啊!家里没有网,到处蹭无线!日子过得真纠结!因为毕设的需求,简单写了一个java程序在线测评程序,当然也可以在本地测试。

二.思路

  首先简单介绍一下思路:

  1.得到java程序的源代码,不需要导入包。得到源码之后在前面加入”import java.util.*;”

  2.通过JavaCompiler对象可以帮助我们将java源代码编译成class文件。

  3.通过DiagnosticCollector对象可以获得编译过程中产生的编译信息。

  4.通过StandardJavaFileManager对象管理生成的class文件,例如文件的存放位置。

  5.StringSourceJavaObject对象可以对java源码进行包装并处理。

数据是控制台输入的,所以要重定向System.in(注意保存标准的输入流);另外程序的输出是到标准的输出流的,为了获得输出结果,我的方法是重定向输出流到ByteArrayOutputStream,然后利用ByteArrayOutputStream构造BufferedReader

  6.运行程序,通过java的反射机制,获得main函数的Method对象。

  7.运行时间的计算通过System.currentTimeMillis()方法。

  8.程序所需内存通过RuntimefreeMemory()方法。

  9.异常信息的获取:StringWriter sw = new StringWriter();  e.printStackTrace(new PrintWriter(sw, true)); sw.toString();

 

三.问题解决

1. JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 出现NullPointerException

  查看部分源码如下:

 

private static final String[] defaultToolsLocation = { "lib", "tools.jar" };
private Class<?> findSystemToolClass(String toolClassName)
        throws MalformedURLException, ClassNotFoundException {
    // try loading class directly, in case tool is on the bootclasspath
    try {
        return Class.forName(toolClassName, false, null);
    } catch (ClassNotFoundException e) {
        trace(FINE, e);

        // if tool not on bootclasspath, look in default tools location (tools.jar)
        ClassLoader cl = (refToolClassLoader == null ? null : refToolClassLoader.get());
        if (cl == null) {
            File file = new File(System.getProperty("java.home"));
            if (file.getName().equalsIgnoreCase("jre"))
                file = file.getParentFile();
            for (String name : defaultToolsLocation)
                file = new File(file, name);

            // if tools not found, no point in trying a URLClassLoader
            // so rethrow the original exception.
            if (!file.exists())
                throw e;

            URL[] urls = { file.toURI().toURL() };
            trace(FINE, urls[0].toString());

            cl = URLClassLoader.newInstance(urls);
            refToolClassLoader = new WeakReference<ClassLoader>(cl);
        }

        return Class.forName(toolClassName, false, cl);
    }
}

 

打印 System.out.println(System.getProperty("java.home")); 如下:

 C:\Program Files (x86)\Java\jre6

defaultToolsLocation = { "lib", "tools.jar" }; 也就是最终到

C:\Program Files (x86)\Java\jre6\lib\tools.jar中寻找tools.jar

然而jre6\lib中没有tools.jar, 而是在C:\Program Files (x86)\Java\jdk\lib中。最直接的办法就是将它复制进去就行了。

 

2.异常信息的获取。

 

3.输入流和输出流的重定向。

 

详细内容请看代码!

四.代码

 

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;

public class CompileAndRunJavaFile {
    public static void main(String[] args) {
        StringBuilder code = new StringBuilder();
        try {
            BufferedReader br = new BufferedReader(new FileReader(new File("测试程序地址")));
            String content;
            while((content = br.readLine()) != null){
                code.append(content).append("\n");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        CompileAndRunJavaFile cr = new CompileAndRunJavaFile();
        cr.compileAndRunJavaFile(code.toString());
        if(cr.isCompileAndRunOK()) {
            System.out.println("运行时间: " + cr.getUseTime() + "ms");
            System.out.println("内存使用: " + cr.getUseMemory() + "kb9");
            System.out.println("运行结果: \n" + cr.getOutMsg());
        } else if(cr.isCompilerError()) {
            System.out.println("编译错误: " + cr.getCE());
        } else if(cr.isRunningError()) {
            System.out.println("运行错误: " + cr.getError());
        }
    }
    //编译错误
    private StringBuilder ce = new StringBuilder();
    public String getCE(){
        return ce.toString();
    }
    
    //内存使用
    private double useMemory = 0.0;
    public double getUseMemory(){
        return useMemory;
    }
    
    //运行时间
    private long useTime = 0;
    public long getUseTime(){
        return useTime;
    }
    //输出信息
    private StringBuilder outMsg = new StringBuilder();
    public String getOutMsg(){
        return outMsg.toString();
    }
    //异常信息
    private String error = null;
    public String getError(){
        return error;
    }
    //是否正常编译并运行
    private boolean isCompileAndRunOK = false; 
    
    public boolean isCompileAndRunOK(){
        return isCompileAndRunOK;
    }
    
    //程序的运行时间, 单位:ms
    private int limitTime = 2000;
    //程序所占内存, 单位 :KB
    private double limitMemory = 256000.0;
    
    public void setLimitTime(int limitTime){
        this.limitTime = limitTime;
    }
    
    public void setLimitMemory(double limitMemory){
        this.limitMemory = limitMemory;
    }
    
    //是否为编译错误
    private boolean isCompilerError = false;
    public boolean isCompilerError(){
        return isCompilerError;
    }
    
    //是否为运行错误
    private boolean isRunningError = false;
    public boolean isRunningError(){
        return isRunningError;
    }
    
    private static final String className = "Main";
    private static final String methodName = "main";
    private String getClassOutput(){
        //设置class文件的存放位置
        if(System.getProperty("java.class.path").contains("bin")) return "bin/";
        else return "./";
    }
    
    private void compileAndRunJavaFile(String code){
        PrintStream ps = null;
        FileInputStream fis = null;
        BufferedReader br = null;
        //保存标准输出流
        InputStream stdIn = System.in;
        //保存标准输入流
        PrintStream stdOut = System.out;
        
        //为源代码导入默认的包
        code = "import java.util.*;\n" + code;
        try {
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            // define the diagnostic object, which will be used to save the
            // diagnostic information
            DiagnosticCollector<JavaFileObject> oDiagnosticCollector = new DiagnosticCollector<JavaFileObject>();
            StandardJavaFileManager fileManager = compiler.getStandardFileManager(oDiagnosticCollector, null, null);
            // set class output location
            fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(new File[] { new File(getClassOutput()) }));
            
            StringSourceJavaObject sourceObject = new CompileAndRunJavaFile.StringSourceJavaObject(className, code);
            Iterable<? extends JavaFileObject> fileObjects = Arrays.asList(sourceObject);
            CompilationTask task = compiler.getTask(null, fileManager, oDiagnosticCollector, null, null, fileObjects);
            boolean result = task.call();
            
            if (result) {
                Runtime runtime = Runtime.getRuntime();
                Class<?> clazz = Class.forName(className);
                Method method = clazz.getMethod(methodName, new Class<?>[]{String[].class});
                
                //重置输入流, 需要存放数据文件的文件名
                fis = new FileInputStream(new File("数据文件地址"));
                System.setIn(fis);
                //重置输出流,需要获得控制台的输出
                ByteArrayOutputStream bao = new ByteArrayOutputStream();
                ps = new PrintStream(bao);
                System.setOut(ps);
                
                long startFreeMemory = runtime.freeMemory();//Java 虚拟机中的空闲内存量
                //执行时间也是无法知道,因为dos执行java命令,程序无法知道它到底执行到那里了,两个进程,互不了解
                long startCurrentTime = System.currentTimeMillis();//获取系统当前时间
                method.invoke(null, new Object[]{null});
                long endCurrentTime = System.currentTimeMillis();
                long endFreeMemory = runtime.freeMemory();
                //内存的使用情况,不是很精确
                useMemory = (startFreeMemory-endFreeMemory)/1024.0;
                if(useMemory > limitMemory) throw new Exception("Out Limit Memory!");
                useTime = endCurrentTime-startCurrentTime;
                if(useTime > limitTime) throw new Exception("Time Limited!");
                
                //获得控制台的输出
                br = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bao.toByteArray())));
                String outc = null;
                while((outc = br.readLine()) != null)
                    outMsg.append(outc).append("\n");
                //正常编译并运行
                isCompileAndRunOK = true;
            } else {
                isCompilerError = true;
                //打印编译的错误信息
                Pattern p = Pattern.compile("Main.java\\D*(\\d+):", Pattern.DOTALL);
                for (Diagnostic<? extends JavaFileObject> oDiagnostic : oDiagnosticCollector.getDiagnostics()){
                    /*信息示例:
                      Compiler Error: Main.java:8: 找不到符号
                         符号: 类 Scanner
                                位置: 类 Main
                    */
                    //将行号减1
                    Matcher m = p.matcher("Compiler Error: " + oDiagnostic.getMessage(null));
                    if(m.find()) {
                        ce.append(m.replaceAll("Main.java " + String.valueOf(Integer.valueOf(m.group(1))-1)) + ":").append("\n");
                    } else {
                        ce.append("Compiler Error: " + oDiagnostic.getMessage(null)).append("\n");
                    }
                }
            }
            
        } catch (Exception e) {
            isRunningError = true;
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw, true));
            Pattern p = Pattern.compile("Main.java\\D*(\\d+)", Pattern.DOTALL);
            Matcher m = p.matcher(sw.toString());
            if(m.find()){
                error = m.replaceAll("Main.java " + String.valueOf(Integer.valueOf(m.group(1))-1) + ":");
            } else {
                error = sw.toString();
            }
        } finally {
            //关闭流
            try {
                if(fis != null)
                    fis.close();
                if(ps != null)
                    ps.close();    
                if(br != null)
                    br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            //恢复输入输出流
            System.setIn(stdIn);
            System.setOut(stdOut);
        }
    }
    
    private class StringSourceJavaObject extends SimpleJavaFileObject {
        private String content = null;
        public StringSourceJavaObject(String name, String content) {
            super(URI.create(name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
            this.content = content;
        }
        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
            return content;
        }
    }
}
View Code

 

五.运行结果显示

1.正常运行

运行时间: 16ms

内存使用: 225.5546875kb

运行结果

5 4 3 2 1 

 

2.编译错误

编译错误: Compiler Error: Main.java 8 找不到符号

符号: 类 Scanner

位置: 类 Main:

Compiler Error: Main.java 8 找不到符号

符号: 类 Scanner

位置: 类 Main:

3.运行错误

(1)运行错误: java.lang.reflect.InvocationTargetException

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

at java.lang.reflect.Method.invoke(Unknown Source)

at com.test.CompileAndRunJavaFile.compileAndRunJavaFile(CompileAndRunJavaFile.java:163)

at com.test.CompileAndRunJavaFile.main(CompileAndRunJavaFile.java:44)

Caused by: java.lang.StackOverflowError

at Main.fun(Main.java 4:)

at Main.fun(Main.java 4:)

 

(2)运行错误: java.lang.reflect.InvocationTargetException

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

at java.lang.reflect.Method.invoke(Unknown Source)

at com.test.CompileAndRunJavaFile.compileAndRunJavaFile(CompileAndRunJavaFile.java:163)

at com.test.CompileAndRunJavaFile.main(CompileAndRunJavaFile.java:44)

Caused by: java.lang.ArrayIndexOutOfBoundsException: 6

at Main.main(Main.java 18:)

... 6 more

 

六.测试程序

public class Main {
    public static void fun(){
        fun();
    }
    public static void main(String[] args) {

        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int[] array = new int[n];
        for(int i=0; i<n; ++i)
            array[i] = scan.nextInt();
        
        for(int i=0; i<n; ++i)
            System.out.print(array[i] + " ");
        System.out.println();
        
        //array[n+1] = 0;
        //fun();
    }
 
}
View Code

 

 

 

 

转载于:https://www.cnblogs.com/hujunzheng/p/5203067.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目录 第一章 需求分析…………………………………………………………1 1.1 项目名称……………………………………………………………1 1.2 系统开发的背景……………………………………………………1 1.3 系统开发的现状……………………………………………………1 1.4 系统开发的目标……………………………………………………1 1.5 系统开发的可行性分析………………………………………………1 第二章 系统分析…………………………………………………………2 2.1 系统分析方法…………………………………………………………2 2.2 数据流程分析…………………………………………………………2 第三章 系统设计与实施…………………………………………………6 3.1 系统设计……………………………………………………………6 3.2 总体设计……………………………………………………………6 3.3 详细设计……………………………………………………………7 3.4 程序设计……………………………………………………………8 3.5 系统实施……………………………………………………………8 3.6 系统测试……………………………………………………………9 第四章 系统运行………………………………………………………11 4.1 系统运行…………………………………………………………11 4.2 结论………………………………………………………………11

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值