据我所知,每个java类都是从单个java文件编译成单个类文件。 (至少只要涉及没有内部类别。)
是否有任何技术原因导致javac
需要访问引用的类来生成类文件?
仅用于检查给定的方法调用是否确实有效,或者是否真的有一些来自引用类的信息需要集成到生成的类文件中?
您能举例说明javac
需要根据引用类的内容生成不同的字节码吗?
有关此主题的任何好文档吗?
答案 0 :(得分:2)
这是一个有点主观的问题,但我喜欢它。
正如您所写,正确的一个原因是早期错误检测。如果编译器没有依赖类的类文件以供参考,则必须假设每个外部引用都是正确的。只能在运行时检测到这些错误。你不想要这个。
虽然这里有漏洞。依赖类可以稍后更改。出于这个原因和其他原因,运行时的可用类定义可能与编译时使用的类定义不同,从而导致运行时错误。
但我们所拥有的比替代方案更好。
在某些情况下,引用类的元素会集成到当前编译单元中,例如“常量”。考虑以下两个类:
// File A1.java
class A1 {
static final String s = "string"; // constant
static String s2 = "string2"; // not constant
static final int i = 5; // constant
}
// File A2.java
class A2 {
public static void main(String args[]) {
System.out.println("A1.s: " + A1.s);
System.out.println("A1.s2: " + A1.s2);
System.out.println("A1.i: " + A1.i );
}
}
编译这两个,然后研究javap -c -l -private A2
的输出并注意以下内容:
A1.s2
的引用,即使 A1.class已删除,也可以执行java A2
答案 1 :(得分:0)
我想您自己回答,编译器需要引用类来检查所有引用的方法是否被正确调用(使用正确的参数),如果它知道这些方法中的内容,它还可以优化一些方法调用
答案 2 :(得分:0)
这是一个原因:如果在库中调用方法x
,编译器如何知道该方法确实存在?怎么知道返回类型?如何知道传入的参数数量是否正确?如何知道你传入的类型是否正确?
在动态语言(如javascript)中,这是在运行时发现的,但缺点是反馈循环更长。你越早发现错误就越好。 Java是静态的,因此此类路径要求使您的反馈循环更短。
答案 3 :(得分:0)
如果我在以下情况下正确理解Jon和锑的评论,A2应该根据A1类的返回类型进行不同的编译。
// File A1.java
class A1 {
public ??? bar(){
return null;
}
}
// File A2.java
class A2 {
public static void main(String args[]) {
foo(A1.bar());
}
private void foo(Integer x){
System.out.println("1");
}
private void foo(String x){
System.out.println("2");
}
}
如果我把事情做对了,编译器必须决定方法foo的调用是指第一个还是第二个定义,并根据A1类中的返回类型为类A2生成不同的字节码。