考虑以下代码
public class myClass{
myClass instanceOfNotYetDefinedClass;
... //etc code
}
我不明白编译器是如何理解的:我告诉它创建一个类,然后它说:"好的!让我看看这个myClass类有什么。哦,这是一个myClass,让我看看这有什么......"等
这可能是一个相当愚蠢的问题,但我真的不明白如何处理这个问题。
答案 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:在解析树上进行两次传递:
方法#2:在解析树上进行一次传递:
还有变化,可能还有其他方法。
但如果您真的想知道Java编译器实际是如何做到的,那么请查看OpenJDK源代码。
对类本身的引用实际上更简单。在您的示例代码中,编译器将在看到public class myClass
的使用之前“看到”myClass
的解析树节点。因此,当遇到后者时,myClass
的条目已经在符号表中。
(在像C这样的老式语言中,函数的声明和定义可以是独立的,但如果在编译单元中先前声明了它,则可以引用它。)
1 - 如果您不知道符号表是什么,那么有关于编译器和编译器构造的好书。