最近在阅读THE STRUCTURE OF THE JAVA VIRTUAL MACHINE时遇到一个疑问
在第 5 页第 5 章。2、
由 Java 虚拟机执行的编译代码使用独立于硬件和操作系统的二进制格式表示,通常(但不一定)存储在文件中,称为类文件格式。
那个括号但不一定是这个原因。
问题是,
在哪种情况下编译的代码不会存储在类文件中?如果它不会存储在类文件中,那么在哪里以及如何?
编辑:请注意,这个问题与 ClassLoader 无关。
最近在阅读THE STRUCTURE OF THE JAVA VIRTUAL MACHINE时遇到一个疑问
在第 5 页第 5 章。2、
由 Java 虚拟机执行的编译代码使用独立于硬件和操作系统的二进制格式表示,通常(但不一定)存储在文件中,称为类文件格式。
那个括号但不一定是这个原因。
问题是,
在哪种情况下编译的代码不会存储在类文件中?如果它不会存储在类文件中,那么在哪里以及如何?
编辑:请注意,这个问题与 ClassLoader 无关。
在java中,类加载器从哪里获取编译的二进制文件取决于它的实现。可以编写一个类加载器,从数据库、网络、内存或任何其他可能的位置加载它的类。
默认的 java URLClassLoader使用目录或 jar 中的文件,所以这就是“典型”的来源,“不一定”只是暗示可能有其他实现。
您似乎对如何在内存中生成 java 类文件更感兴趣,所以这里是:
public class CompileSourceInMemory {
public static void main(String args[]) throws IOException {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
StringWriter writer = new StringWriter();
PrintWriter out = new PrintWriter(writer);
out.println("public class HelloWorld {");
out.println(" public static void main(String args[]) {");
out.println(" System.out.println(\"This is in another java file\");");
out.println(" }");
out.println("}");
out.close();
JavaFileObject file = new JavaSourceFromString("HelloWorld", writer.toString());
Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(file);
CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, compilationUnits);
boolean success = task.call();
if (success) {
try {
Class.forName("HelloWorld").getDeclaredMethod("main", new Class[] { String[].class }).invoke(null, new Object[] { null });
} catch (ClassNotFoundException e) {
System.err.println("Class not found: " + e);
} catch (NoSuchMethodException e) {
System.err.println("No such method: " + e);
} catch (IllegalAccessException e) {
System.err.println("Illegal access: " + e);
} catch (InvocationTargetException e) {
System.err.println("Invocation target: " + e);
}
}
}
}
class JavaSourceFromString extends SimpleJavaFileObject {
final String code;
JavaSourceFromString(String name, String code) {
super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension),Kind.SOURCE);
this.code = code;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return code;
}
}
来源: 内存编译
这会在内存中生成一个类,而没有 Java 源代码或编译类的任何外部表示。
是的,这个问题是关于 Classloader 的!
Classloader 是 JVM 引入类的(唯一)方式。这些类可以在文件、JAR 档案、网络上的某个地方、数据库 blob、共享内存、纸带上(如果您的机器有纸带阅读器),甚至可以动态生成。
所以,这就是你的问题的答案。
标准编译器用于编写类文件,但正如 Peter 评论的那样,不一定如此。而且,最重要的是,仅仅因为 javac 命令写入类文件并不意味着我们必须使用这些文件。通常将它们打包在一个 JAR 中,然后改用它。