Thay vì viết nhiều mã để Java có thể thực thi dưới dạng nguồn, bạn có một vài tùy chọn:
Sử dụng Scala! Bạn có biết rằng Scala được xây dựng trên Java không? Nó có một thông dịch viên và trình biên dịch. Bạn có thể chạy một kịch bản, một trình bao hoặc biên dịch và chạy nó. Scala và Java làm việc liền mạch với nhau. Cả hai biên dịch sang cùng một bytecode và chạy trên một JVM. Có, ngôn ngữ sẽ cảm thấy kỳ lạ bởi vì Scala giống như một chéo giữa Java, R và Python, nhưng hầu hết các ngôn ngữ cốt lõi là không thay đổi và tất cả các gói Java có sẵn. Hãy thử Scala. Nếu bạn đang sử dụng Linux, bạn cũng có thể quan sát Spark, ngay cả đối với một máy.
Nếu bạn nhấn mạnh vào việc chỉ sử dụng Java, bạn có thể tạo chương trình lai thực hiện hai việc (tôi đã thực hiện việc này trước đây): biên dịch mã và chạy nó. Tập lệnh thực thi hoặc thậm chí là một tập lệnh bash có thể thực hiện công việc lấy các tệp nguồn và làm cho chúng có thể thực thi được. Nếu bạn đang muốn tạo một trình bao Java, thì bạn cần tạo một trình biên dịch/trình nạp thời gian động, nhưng bạn chỉ cần sử dụng những gì Java/Oracle đã cung cấp cho chúng ta. Hãy tưởng tượng chèn cú pháp Java từ một tệp mà tôi đặt một câu lệnh in. Bạn có thể có bất cứ điều gì trong đó bạn muốn miễn là nó biên dịch. Xem ví dụ sau:
package util.injection;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class Compiler {
static final long t0 = System.currentTimeMillis();
public static void main(String[] args) {
StringBuilder sb = new StringBuilder(64);
String packageName = "util";
String className = "HelloWorld";
sb.append("package util;\n");
sb.append("public class HelloWorld extends " + Function.class.getName() + " {\n");
sb.append(" public void test() {\n");
sb.append(" System.out.println(\"Hello from dynamic function!\");\n");
sb.append(" }\n");
sb.append("}\n");
String code = sb.toString();
String jarLibraryFile = "target/myprojectname.jar";
Function dynFunction = code2class(packageName, className, code, jarLibraryFile);
dynFunction.test();
}
public static Function code2class(String packageName, String className, String code, String jarLibraryFile) {
String wholeClassName = packageName.replace("/", ".") + "." + className;
String fileName = wholeClassName.replace(".", "/") + ".java";//"testcompile/HelloWorld.java";
File javaCodeFile = new File(fileName);
string2file(javaCodeFile, code);
Function dynFunction = null;
try {
boolean success = compile(jarLibraryFile, javaCodeFile);
/**
* Load and execute
* ************************************************************************************************
*/
System.out.println("Running... " + (System.currentTimeMillis() - t0) + " ms");
Object obj = load(wholeClassName);
// Santity check
if (obj instanceof Function) {
dynFunction = (Function) obj;
// Run it
//Edit: call dynFunction.test(); to see something
}
System.out.println("Finished... " + (System.currentTimeMillis() - t0) + " ms");
} catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException exp) {
exp.printStackTrace();
}
return dynFunction;
}
public static boolean compile(String jarLibraryFile, File javaCodeFile) throws IOException {
/**
* Compilation Requirements
* ********************************************************************************************
*/
System.out.println("Compiling... " + (System.currentTimeMillis() - t0) + " ms");
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
// This sets up the class path that the compiler will use.
// I've added the .jar file that contains the DoStuff interface within in it...
List<String> optionList = new ArrayList<>(2);
optionList.add("-classpath");
optionList.add(System.getProperty("java.class.path") + ";" + jarLibraryFile);
Iterable<? extends JavaFileObject> compilationUnit
= fileManager.getJavaFileObjectsFromFiles(Arrays.asList(javaCodeFile));
JavaCompiler.CompilationTask task = compiler.getTask(
null,
fileManager,
diagnostics,
optionList,
null,
compilationUnit);
fileManager.close();
/**
* *******************************************************************************************
* Compilation Requirements *
*/
if (task.call()) {
return true;
/**
* ***********************************************************************************************
* Load and execute *
*/
} else {
for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
System.out.format("Error on line %d in %s%n",
diagnostic.getLineNumber(),
diagnostic.getSource().toUri());
System.out.printf("Code = %s\nMessage = %s\n", diagnostic.getCode(), diagnostic.getMessage(Locale.US));
}
}
return false;
}
public static void string2file(File outputFile, String code) {
if (outputFile.getParentFile().exists() || outputFile.getParentFile().mkdirs()) {
try {
Writer writer = null;
try {
writer = new FileWriter(outputFile);
writer.write(code);
writer.flush();
} finally {
try {
writer.close();
} catch (Exception e) {
}
}
} catch (IOException exp) {
exp.printStackTrace();
}
}
}
public static Object load(String wholeClassName) throws IllegalAccessException, InstantiationException, ClassNotFoundException, MalformedURLException {
// Create a new custom class loader, pointing to the directory that contains the compiled
// classes, this should point to the top of the package structure!
URLClassLoader classLoader = new URLClassLoader(new URL[]{new File("./").toURI().toURL()});
// Load the class from the classloader by name....
Class<?> loadedClass = classLoader.loadClass(wholeClassName);
// Create a new instance...
Object obj = loadedClass.newInstance();
return obj;
}
}
..
package util.injection;
public class Function {
private static final long serialVersionUID = 7526472295622776147L;
public void test() {
System.out.println("Hello from original Function!");
}
public int getID() {
return -1;
}
public void apply(float[] img, int x, int y) {
}
public double dot(double[] x, double[] y) {
return 0;
}
}
Ahh như vậy với Java các tập tin .class sẽ phải được lưu trữ ở đâu và được tham chiếu bởi thực thi vẫn còn? –
Có, đó là chính xác và bạn phải chắc chắn rằng classpath là chính xác trước khi chạy nó. Vì vậy, nó là thực tế hơn để sử dụng một kịch bản sh thường. –
Thật thú vị. Tôi không biết bạn có thể vượt qua các đối số sau khi shebang quá.Tôi đoán đó là những gì tôi nhận được để được tự dạy haha. Đã phê duyệt câu trả lời! –