聽名字是不是有點兒脫褲子放屁的感覺,其實就是寫一個允許你無需使用類或者方法包裝來執行 Java 語句(類似Java 9中的Jshell),就像是一些腳本語言(js,python)的一些解釋執行過程一樣
目標
我們可以定義一個自己的文本文件,后綴名為j,比如Foo.j,在這個文件中,我們可以像python那樣直接寫執行語句,而不用去定義類或者方法,比如如下:
int m = 10; int n = 1; System.out.println(m+n); int x = getSum(1,2); System.out.println(x); //進行方法的定義 methods: int getSum(int a,int b) { //hh(); return a+b; } void hh() { System.out.println("hh"); }
可以看到,我們並沒有聲明類,這樣當我們在用Java寫一些算法,或者驗證某些東西的時候就會方便一點點.
思路
其實我們可以將j文件內容提取出來,然后將過程化的語句包裝在main方法里面,定義的方法放在外面,然后進行編譯執行就ok了,把這整個過程用我們的代碼實現下就可以了
實踐
根據剛才的思路,我們需要寫幾個方法,第一將我們定義的j文件轉成String,第二創建Java文件,最后編譯並自動執行Java文件,代碼如下,里面含有注釋:
public class Main { private static String rootPath = System.getProperty("user.dir") + "\\"; private static String jName; public static void main(String[] args) throws IOException { //獲取j文件名稱,並將j文件轉成String String jStr = jFileToString(args[0]); //創建Java文件 createJavaFile(jStr); //編譯並加載 loadAndCompile(); } /** * 將j文件轉成String * @param param * @return * @throws IOException */ private static String jFileToString(String param) throws IOException { jName = param.replace(".j", ""); String jFilePath = rootPath + param; File javaFile = new File(jFilePath); if (javaFile.isDirectory()) { throw new IOException("j file does not a folder"); } InputStreamReader isr = new InputStreamReader(new FileInputStream(javaFile), StandardCharsets.UTF_8); BufferedReader bReader = new BufferedReader(isr); StringBuilder sb = new StringBuilder(); String s; while ((s = bReader.readLine()) != null) { sb.append(s).append("\n"); } bReader.close(); return sb.toString(); } /** * 創建Java文件 * @param jStr * @throws IOException */ private static void createJavaFile(String jStr) throws IOException { jName = jName.replace(".j", ""); String jFilePath = rootPath + jName + ".java"; File javaFile = new File(jFilePath); if (javaFile.exists()) { javaFile.delete(); } if (!javaFile.createNewFile()) { throw new IOException("java file create fail"); } //抽取方法 String methods = jStr.substring(jStr.indexOf("methods:")); methods = methods.replaceFirst("methods:", ""); jStr = jStr.substring(0, jStr.indexOf("methods:")); String st = "void st(){" + jStr + "}"; String main = "import java.io.*;\npublic class " + jName + " \n{public static void main(String[] args) throws Exception { \n new " + jName + "().st();\n}" + methods + st + "\n}"; //輸出到文件 OutputStreamWriter oStreamWriter = new OutputStreamWriter(new FileOutputStream(javaFile), StandardCharsets.UTF_8); oStreamWriter.append(main); oStreamWriter.close(); } /** * 編譯並加載 * @throws IOException */ private static void loadAndCompile() throws IOException { //調用系統編譯器 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); int results = compiler.run(null, null, null, rootPath + jName + ".java"); if (results != 0) { throw new RuntimeException("compiler exception"); } //使用命令執行 Process process = Runtime.getRuntime().exec("java " + jName, null, new File(rootPath)); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); //輸出執行結果 String str; while ((str = bufferedReader.readLine()) != null) { System.out.println(str); } } }
寫完后我們打成Jar包,清單文件里面配置好主方法,記住一個重點就是上面我們用到了一個Jar包-tools.jar,這個Jar包在jdk環境下是有的,也就是開發環境里面,但是在jre環境是沒有的,所以我們要講jdk里面lib文件夾下的tools.jar復制到jre文件夾下面的lib里面去,
就大功告成了!
效果展示
當前文件夾下有我們定義好的Java腳本文件Tes.j我們右鍵打開控制台執行:
可以看到我們的腳本已經被執行成功了!
總結
寫這么個看似無用的小東西其實是為了讓大伙懂一些編程語言執行的一些過程,有關解釋器啥的,但是上面寫的比較粗糙,可以不用去生成java文件,然后的話導包也沒有導入很多其他的包,就如同python,是被其他語言所編寫的解釋器如CPython C語言編寫的,Jython Java語言編寫的,來解釋執行的,你甚至可以自己定義一門語言,然后按照自己喜歡的語法,最后自己寫一個解釋器來執行!當然你會遇到很多困難.
一起加油,我也是一個小菜鳥,希望大家共同進步!