当你自己有一个类`c`时,Java编译器如何工作?

时间:2016-04-30 22:54:15

标签: java compilation

考虑以下代码

public class myClass{
    myClass instanceOfNotYetDefinedClass;
    ... //etc code
}

我不明白编译器是如何理解的:我告诉它创建一个类,然后它说:"好的!让我看看这个myClass类有什么。哦,这是一个myClass,让我看看这有什么......"等

这可能是一个相当愚蠢的问题,但我真的不明白如何处理这个问题。

2 个答案:

答案 0 :(得分:2)

要查看编译器的功能,请使用javac编译该类并在其上运行javap。在课堂上这样做可以得到以下结果:

public class myClass {
    myClass instanceOfNotYetDefinedClass;
    public myClass();
}

public myClass();是默认构造函数,在这里无关紧要。从这里,我们可以看到编译器只是将myClass类型的字段附加到myClass。这是如何运作的?由于myClass是代码范围中的现有类,因此编译器知道它将在运行时定义。因此,它只是保留了这个定义。在运行时,调用myClass.instanceOfNotYetDefinedClass会为您提供字段值 - 如果您没有初始化,则为null,或者具有自己字段的myClass实例。这里没有无限的递归或冲突,除非你做到这一点,例如在构造函数中调用new myClass()

答案 1 :(得分:1)

编译器可以通过多种方式执行此操作:

方法#1:在解析树上进行两次传递:

  • 在第1遍中,找到所有声明和所有范围边界,并填充符号表 1
  • 在第2遍中,找到所有标识符引用并根据符号表解析它们。

方法#2:在解析树上进行一次传递:

  • 每当遇到声明时创建一个符号表条目
  • 遇到标识符引用时:
    1. 尝试在符号表
    2. 中解决此问题
    3. 如果解决方案失败,请将其添加到稍后要解决的列表中
  • 在传递结束时,重新访问列表中的所有标识符,并尝试针对(现在完整的)符号表再次解析它们。

还有变化,可能还有其他方法。

但如果您真的想知道Java编译器实际是如何做到的,那么请查看OpenJDK源代码。

对类本身的引用实际上更简单。在您的示例代码中,编译器将在看到public class myClass的使用之前“看到”myClass的解析树节点。因此,当遇到后者时,myClass的条目已经在符号表中。

(在像C这样的老式语言中,函数的声明和定义可以是独立的,但如果在编译单元中先前声明了它,则可以引用它。)

1 - 如果您不知道符号表是什么,那么有关于编译器和编译器构造的好书。