如果我有一个类SOmeClass,使用方法someMethod,在下面的代码中,编译器如何读取类成员someConstant?
Class SomeClass{
private int someConstant = someMethod(3); //3 is arbitrary
private int anotherConstant;
SomeClass(){
//constructor
anotherConstant = someConstant;
}
public int someMethod(int an_int_value){
//something
return new_int;
}
这个问题是关于我对编译器如何工作的困惑。以及机器如何读取代码。在实例化类之前,常量someConstant无法启动,因为编译器需要知道someMethod所执行的方法。但是构造函数无法完成,因为另一个元素也需要具有这个未知值。在我看来(没有计算机科学经验的人),这是一个捕获22的情况。这个问题不仅限于Java。这只是我最熟悉的语言。
答案 0 :(得分:4)
Java中的对象实例化是一个多步骤过程。首先,将类中的每个字段初始化为其默认值(0,false或null,视情况而定)。接下来,具有初始化程序的每个字段按顺序初始化为该值。如果这意味着调用任何方法,那么调用这些方法时,字段要么保持默认值(如果尚未触及它们),要么将它们初始化为值。最后,调用构造函数。
请注意,这意味着在构造函数运行之前分配对象的内存。为了使这种方法有效,这是必要的。
答案 1 :(得分:0)
不是Java VM的专家,我仍然会尝试回答你的问题:
您的问题实际上不是涉及编译器的问题 - 编译器只会将您的可读Java代码转换为二进制指令。除非编译器“足够聪明”以在代码中找到循环依赖项,否则在运行时会出现未初始化变量的问题。
你的所有值都不是常量 - 它们必须被声明为final
,如果你以这种方式声明它,你将无法设置anotherConstant
。它们都是变量。
首先,您的班级将被加载到内存中。因此SomeClass
的基本内存布局将是已知的,someMethod()
的功能也是如此。如果您声明了静态变量,它们现在也会被初始化,但您无法调用像someMethod
这样的实例方法。
当您实例化SomeClass
类型的对象时,将首先设置所有成员变量,因此someConstant
将不再是未知的。由于someMethod
的功能也是已知的,因此这应该不是问题。如果您在someMethod
中的某个时刻引用未声明的变量,则会引发NullPointerException
。
最后,调用构造函数。此时,所有成员变量都可用,因此它们都可以顺利运行。再次 - 如果有任何未声明的变量,将抛出NullPointerException
。在你的例子中,不应该有任何。
答案 2 :(得分:0)
您似乎将编译器与运行时混淆。 someMethod()
所做的是在编译时确定并存储在输出的.class文件中。运行时读入这些.class文件并从中构建类定义。因此,在您尝试实例化SomeClass
之前,它完全了解someMethod()的作用。在类的方法具有定义之前,构造函数不需要完成运行就没有限制。
java所做的是按照它们声明的顺序运行所有初始化程序,然后启动实际构造函数中的内容。考虑:
private Integer foo = getFoo();
private Integer bar = Integer.valueOf(4);
private Integer getFoo() {return bar;}
当我们完成时,foo将为null,因为它已被声明为第一个并且当我们分配它时bar仍为null。
private Integer bar = Integer.valueOf(4);
private Integer foo = getFoo();
private Integer getFoo() {return bar;}
这种方式foo在施工完成后将为4!无论哪种方式,运行时都可以在构造函数完成之前查找getFoo()方法的定义,因为编译器会在类文件中定义它。