编译器+类间引用:javac如何快速完成C ++编译器的缓慢操作?

时间:2012-02-12 04:15:31

标签: java compiler-construction language-design

enter link description here如果你有一堆所有相互引用并使用彼此方法的类,那么java编译器如何能够如此快速地解决类间引用?

我知道C ++编译器在这方面是如何工作的:每个.cpp文件都是单独编译的,他们使用那些糟糕的.h文件来声明类字段/方法,这样每次重新解析同一组文件/或编译器必须支持预编译的头文件。

但是Java没有这样做,并且在类接口/实现的程序源中没有像Turbo Pascal将它们分开的方式分离。

我可以看到,如果你有一个类Foo并且它引用的是Bar,Baz,Quux类,它们都在一个单独的barbazquux.jar文件中,那么事情就会很简单:.jar文件已经被编译了,所以当Foo.java被编译时,它可以直接查看barbazquux.jar中的.class文件。

但是如果你有循环类引用,并且类Foo引用引用类Foo的类Bar,它如何编译Foo.java而不必首先编译Bar.java然后决定它必须编译Foo.java并获取卡在一个循环?

Java编译器如何处理类间引用?


编辑:yair指出another question的答案含糊不清地提及多通道编译器。好的,所以有多个通行证。每次传递到底发生了什么?Java如何快速编译?是否必须在每次传递时重新解析每个文件,或者它是否存储抽象语法树以节省时间,或者是什么?

2 个答案:

答案 0 :(得分:0)

C ++必须解析外部类声明的源代码,通常在.hpp文件中。 Java处理已编译的外部类声明的目标代码。 Java所做的更像是使用包的语言,例如Ada,Modula-3,......这也是大多数C / C ++编译器也有'预编译头'的原因。

答案 1 :(得分:-1)

C ++的语法要复杂得多,表达部分含糊不清。所以Javac在解析方面更有效率。此外,C ++还有更精细的编译单元。即使预编译,C ++也包含递归可见性:包括包括可以使用的定义名称的包含。在Java中,如果使用导入类的父类,则需要显式导入它。

循环类引用是有问题的。在Java中,可以假设一个类存在,即使该类尚未编译,也可以作为前提条件。但java编译器更令人印象深刻,能够同时编译它们。同样是因为循环依赖。 JVM byte code invoke instructions使用方法名称,因此可以推测性地编译第一个类。

public class A {
    public static void a(int i) {
        System.out.println("a(" + i + ")");
        if (i < 10)
            B.b(i + 2);
    }
}

public class B {
    public static void b(int i) {
        System.out.println("b(" + i + ")");
        if (i < 10)
            A.a(i + 1);
    }
}

public static void main(String... args) {
    B.b(0);
}