当Java编译器内部有一个类“c”时,它是如何工作的?

当Java编译器内部有一个类“c”时,它是如何工作的?,java,compilation,Java,Compilation,考虑以下代码 public class myClass{ myClass instanceOfNotYetDefinedClass; ... //etc code } 我不明白编译器是如何理解的:我告诉它创建一个类,然后它说:“好吧!让我看看这个myClass类有什么。哦,它是一个myClass,让我看看它有什么…”等等 这可能是一个非常愚蠢的问题,但我真的不明白如何处理这个问题。要了解编译器的功能,请使用javac编译该类并在其上运行javap。在课堂上这样做会产生以下效果:

考虑以下代码

public class myClass{
    myClass instanceOfNotYetDefinedClass;
    ... //etc code
}
我不明白编译器是如何理解的:我告诉它创建一个类,然后它说:“好吧!让我看看这个myClass类有什么。哦,它是一个myClass,让我看看它有什么…”等等


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

要了解编译器的功能,请使用javac编译该类并在其上运行javap。在课堂上这样做会产生以下效果:

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

公共myClass()
是一个默认构造函数,与此处无关。从这里,我们可以看到编译器只是将类型为
myClass
的字段附加到
myClass
。这是怎么回事?由于
myClass
是代码作用域中的现有类,编译器知道它将在运行时定义。因此,它只是将这一定义保持原样。在运行时,调用
myClass.instanceOfNotYetDefinedClass
会为您提供字段的值-如果您不初始化它,则该值为
null
,或者是具有自己字段的
myClass
实例。这里没有无限递归或冲突,除非您在构造函数中调用
new myClass()

要查看编译器的功能,请使用javac编译类并在其上运行javap。在课堂上这样做会产生以下效果:

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

公共myClass()
是一个默认构造函数,与此处无关。从这里,我们可以看到编译器只是将类型为
myClass
的字段附加到
myClass
。这是怎么回事?由于
myClass
是代码作用域中的现有类,编译器知道它将在运行时定义。因此,它只是将这一定义保持原样。在运行时,调用
myClass.instanceOfNotYetDefinedClass
会为您提供字段的值-如果您不初始化它,则该值为
null
,或者是具有自己字段的
myClass
实例。这里没有无限递归或冲突,除非您在构造函数中调用
new myClass()

编译器有多种方法可以做到这一点:

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

  • 在过程1中,查找所有声明和所有范围边界,并填充符号表1
  • 在过程2中,找到所有标识符引用并根据符号表解析它们
方法#2:对解析树进行一次遍历:

  • 每当遇到声明时,创建符号表项
  • 遇到标识符引用时:
  • 尝试在符号表中解析它
  • 如果解决失败,请将其添加到稍后要解决的列表中
  • 在过程结束时,重新访问列表中的所有标识符,并尝试根据(现在已完成的)符号表再次解析它们
还有一些变化,可能还有其他的方法

但是如果您真的想知道Java编译器是如何实现的,请查看OpenJDK源代码


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


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



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

编译器可以通过多种方式实现这一点:

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

  • 在过程1中,查找所有声明和所有范围边界,并填充符号表1
  • 在过程2中,找到所有标识符引用并根据符号表解析它们
方法#2:对解析树进行一次遍历:

  • 每当遇到声明时,创建符号表项
  • 遇到标识符引用时:
  • 尝试在符号表中解析它
  • 如果解决失败,请将其添加到稍后要解决的列表中
  • 在过程结束时,重新访问列表中的所有标识符,并尝试根据(现在已完成的)符号表再次解析它们
还有一些变化,可能还有其他的方法

但是如果您真的想知道Java编译器是如何实现的,请查看OpenJDK源代码


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


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



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

Java是开源的,请看源代码。;-)编译器不会这样自言自语。Java是开源的,看看源代码。;-)编译器不会这样自言自语。