前言
在学习反射的时候无意间看到:让java变成脚本语言这一文,按照他的思路我完善了一下代码。实现了JAVA的脚本化和动态化,初学者可以像使用python一样在控制窗口内逐行进行编程。
基本功能及使用方法
使用cmd打开javacafe.jar,进入程序
实现
1.使用ToolProvider.getSystemJavaCompiler()获得JavaCompiler类,对输入程序进行动态编译。
2.使用反射机制获得run方法运行程序输出结果。
详细代码
主程入口start.java
package javacafe;
import java.util.Scanner;
import java.util.regex.Pattern;
public class start {
public static String ImportStr = "";
public static String CodeStr = "";
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (true) {
String code = scanner.nextLine();
javaCompilerUtil javaCompilerUtil = new javaCompilerUtil();
// 判断是否为输出语句
String patterprint = "^print.*$";
if (Pattern.matches(patterprint, code)) {
// 合篇编译+输出
code = code.replace(" ", "");
code = code.replace("print", "");
String c1 = "System.out.println(\"";
//String c2 = code + "=\"+" + code + ");"; 加入括号可以输出print a+b
String c2 = code + "=\"+(" + code + "));";
code = CodeStr + c1 + c2;
javaCompilerUtil.CompileAndRun(ImportStr, code);
} else if (code.equals("run")) {
// 合篇编译
javaCompilerUtil.CompileAndRun(ImportStr, CodeStr);
} else {
// 如果是import语句就进行验包
String pattern = "^import.*$";
if (Pattern.matches(pattern, code)) {
if (javaCompilerUtil.Importable(code)) {
// System.out.println("引用可以编译");
ImportStr += code + ";";
}
} else {
// 判断是否符合语法。
if (javaCompilerUtil.Compilable(ImportStr, CodeStr + code + ";")) {
// System.out.println("内容可以编译");
CodeStr += code + ";";
}
}
}
}
}
}
编译器工具类javaCompilerUtil.java
package javacafe;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.List;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;
public class javaCompilerUtil {
static JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
static final List<String> list = Arrays.asList("-d", System.getProperty("user.dir"));
static final String fileurl = System.getProperty("user.dir") + "/";
public boolean Compilable(String ipt, String str) {
try {
String CLASS_CONTENT = ipt + "public class CompilableClass{public static void run(){##;}}";
JavaFileObject fileObject = new JavaStringObject("CompilableClass", CLASS_CONTENT.replace("##", str));
CompilationTask task = javaCompiler.getTask(null, null, null, list, null, Arrays.asList(fileObject));
return task.call();
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean Importable(String str) {
try {
String CLASS_CONTENT = "##;public class ImportableClass{public static void run(){}}";
JavaFileObject fileObject = new JavaStringObject("ImportableClass", CLASS_CONTENT.replace("##", str));
CompilationTask task = javaCompiler.getTask(null, null, null, list, null, Arrays.asList(fileObject));
return task.call();
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public void CompileAndRun(String ImportStr, String CodeStr) {
String CLASS_CONTENT = "public class CompileAndRunClass{public static void run(){##}}";
String fileStr = ImportStr + CLASS_CONTENT.replace("##", CodeStr);
JavaFileObject fileObject = new JavaStringObject("CompileAndRunClass", fileStr);
CompilationTask task = javaCompiler.getTask(null, null, null, list, null, Arrays.asList(fileObject));
if (!task.call()) {
// System.out.println("编译失败!");
} else {
// System.out.println("编译成功!");
// 成功以后,就利用反射来执行这个类了
try {
URL[] urls = new URL[] { new URL("file:/" + fileurl) };
URLClassLoader classLoader = new URLClassLoader(urls);
Class<?> clazz = classLoader.loadClass("CompileAndRunClass");
Method method = clazz.getDeclaredMethod("run");
method.invoke(clazz.newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
其他工具类JavaStringObject.java
package javacafe;
import java.io.IOException;
import java.net.URI;
import javax.tools.SimpleJavaFileObject;
public class JavaStringObject extends SimpleJavaFileObject {
private String code;
public JavaStringObject(String name, String code) {
super(URI.create(name + ".java"), Kind.SOURCE);
this.code = code;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors)
throws IOException {
return code;
}
}