简单java在线测评程序

简单java程序在线测评程序

v一.前言

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

v二.思路

  首先简单介绍一下思路:

  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.程序所需内存: 通过Runtime的freeMemory()方法。

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

 

v三.问题解决

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.输入流和输出流的重定向。

 

详细内容请看代码!

v四.代码

 

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;
        }
    }
}

 

五.运行结果显示

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

 

v六.测试程序

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();
    }

}

 

 

时间: 2024-07-30 10:13:54

简单java在线测评程序的相关文章

Java基于UDP协议实现简单的聊天室程序_java

最近比较闲,一直在抽空回顾一些Java方面的技术应用. 今天没什么事做,基于UDP协议,写了一个非常简单的聊天室程序. 现在的工作,很少用到socket,也算是对Java网络编程方面的一个简单回忆.  先看一下效果:   实现的效果可以说是非常非常简单,但还是可以简单的看到一个实现原理.  "聊天室001"的用户,小红和小绿相互聊了两句,"聊天室002"的小黑无人理会,在一旁寂寞着.  看一下代码实现:  1.首先是消息服务器的实现,功能很简单:•将客户端的信息(进

java网络编程-Java写了个简单的网络编程程序,运行没有结果,求解谢谢!

问题描述 Java写了个简单的网络编程程序,运行没有结果,求解谢谢! import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.io.PrintWriter; import ja

java代码-一个简单java程序,用链表实现多项式相加

问题描述 一个简单java程序,用链表实现多项式相加 public class Literal { private int coefficient; private int exponent; Literal next = null;// 默认是null public Literal() { this(0, 0); } public Literal(int coefficient, int exponent) { setCoe(coefficient); setExp(exponent); th

初学java,自己用java写了一个简单的注册登录程序,没报错但有问题,希望能帮忙指点。

问题描述 初学java,自己用java写了一个简单的注册登录程序,没报错但有问题,希望能帮忙指点. import java.util.Scanner; class Yanzheng{ private String n; private String p; public void setNa(String na){ this.n = na; } public void setPa(String pa){ this.p = pa; } public String getNa(){ return n;

java写出简单的表单程序

这是java程序下 import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class FormDemo extends HttpServlet{  public void doGet(HttpServletRequest request,HttpServletResponse response){     try{    response.setContentType("text/html;ch

php简单的在线聊天室程序

php教程简单的在线聊天室程序 index.php <html> <head><Title> 在线聊天 </title></head> <!-- frames --> <frameset  rows="70%,*" BORDER="0">     <frame name="top" src="_b.php" marginwidth=&qu

5、编写一个简单的JAVA Application 应用程序,编写两个方法area1,area2计算圆柱体的表面积和体积,圆柱体半径R=5,高H=10,并输出计

问题描述 5.编写一个简单的JAVAApplication应用程序,编写两个方法area1,area2计算圆柱体的表面积和体积,圆柱体半径R=5,高H=10,并输出计算结果急求答案谢谢

面向Java Web应用程序的OpenID,第2部分

为单点登录身份验证编写OpenID提供者 简介:本文中,您将学习如何使用 OpenID 保护 Java Web 应用程序资源,以防止被没有经过身份验证的用户的损害.在这个介绍 OpenID 身份验证规范的系列的第 2 部分中,Steve Perry 讲解如何使用 openid4java 库为单点登录场景创建 OpenID 提供者.通过在"闭环"架构中构建作为 OpenID 提供者的应用程序,可以让最终用户只需登录一次,即可访问多个应用程序.另外,您还将学习如何使用 OpenID Att

面向Java Web应用程序的OpenID,第1部分

在Java Web应用程序中使用OpenID身份验证 OpenID 是一套分散式身份验证系统.通过 OpenID 我可以证明自己拥有类似 http://openid.jstevenperry.com/steve 这样的 URL,而且可以使用经验证的身份登录任何支持 OpenID 的站点 - 比如 Google.Slashdot 或 Wordpress.OpenID 对终端用户来说无疑是个不错的工具.但是对 OpenID 的使用引发我产生这样的想法:"如果使用 OpenID 为我给客户编写的基于