简单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.程序所需內存:?通過Runtime的freeMemory()方法。
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 bootclasspathtry {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;}//程序的運行時間, 單位:msprivate int limitTime = 2000;//程序所占內存, 單位 :KBprivate 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 informationDiagnosticCollector<JavaFileObject> oDiagnosticCollector = new DiagnosticCollector<JavaFileObject>();StandardJavaFileManager fileManager = compiler.getStandardFileManager(oDiagnosticCollector, null, null);// set class output locationfileManager.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*///將行號減1Matcher 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
總結
以上是生活随笔為你收集整理的简单java在线测评程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 玩具店适合开在什么地方 开店选址其实
- 下一篇: 涉税信息是什么意思