2

据我了解,每个单个 java 类都是从单个 java 文件编译为单个类文件。(至少只要不涉及内部类。)

是否有任何技术原因javac需要访问引用的类来生成类文件?

是否仅用于检查给定的方法调用是否确实有效,或者是否确实有一些来自引用类的信息需要集成到生成的类文件中?

您能否举一个示例,其中javac需要根据引用类的内容生成不同的字节码?

关于这个主题的任何好的文档?

4

4 回答 4

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.s 和 A1.i 的引用包括实际值
  • 如果删除了对A1.s2then的引用,即使A1.class 被删除java A2也可以执行
于 2013-10-10T22:08:51.937 回答
0

我想你自己回答了,编译器需要引用类来检查所有引用的方法是否被正确调用(使用正确的参数),如果它知道这些方法中的内容,它也可以优化一些方法调用

于 2013-10-10T21:47:15.040 回答
0

如果我在以下情况下正确理解 Jon 和 Antimony 的评论,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 生成不同的字节码。

于 2013-10-10T22:52:01.183 回答
0

原因如下:如果调用x库中的方法,编译器如何知道该方法确实存在?它怎么知道返回类型?它怎么知道你传入的参数个数是正确的?它怎么知道你传入的类型是正确的?

在动态语言(如 javascript)中,这是在运行时发现的,但缺点是反馈循环更长。越早发现错误越好。Java 是静态的,因此这个类路径要求使您的反馈循环更短。

于 2013-10-10T21:56:30.993 回答