关于Java中的类成员的问题

时间:2011-01-14 00:57:45

标签: java oop compiler-construction constructor

如果我有一个类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;
                      }

这个问题是关于我对编译器如何工作的困惑。以及机器如何读取代码。在实例化类之前,常量some​​Constant无法启动,因为编译器需要知道someMethod所执行的方法。但是构造函数无法完成,因为另一个元素也需要具有这个未知值。在我看来(没有计算机科学经验的人),这是一个捕获22的情况。这个问题不仅限于Java。这只是我最熟悉的语言。

3 个答案:

答案 0 :(得分:4)

Java中的对象实例化是一个多步骤过程。首先,将类中的每个字段初始化为其默认值(0,false或null,视情况而定)。接下来,具有初始化程序的每个字段按顺序初始化为该值。如果这意味着调用任何方法,那么调用这些方法时,字段要么保持默认值(如果尚未触及它们),要么将它们初始化为值。最后,调用构造函数。

请注意,这意味着在构造函数运行之前分配对象的内存。为了使这种方法有效,这是必要的。

答案 1 :(得分:0)

不是Java VM的专家,我仍然会尝试回答你的问题:

  1. 您的问题实际上不是涉及编译器的问题 - 编译器只会将您的可读Java代码转换为二进制指令。除非编译器“足够聪明”以在代码中找到循环依赖项,否则在运行时会出现未初始化变量的问题。

  2. 你的所有值都不是常量 - 它们必须被声明为final,如果你以这种方式声明它,你将无法设置anotherConstant。它们都是变量。

  3. 首先,您的班级将被加载到内存中。因此SomeClass的基本内存布局将是已知的,someMethod()的功能也是如此。如果您声明了静态变量,它们现在也会被初始化,但您无法调用像someMethod这样的实例方法。

  4. 当您实例化SomeClass类型的对象时,将首先设置所有成员变量,因此someConstant将不再是未知的。由于someMethod的功能也是已知的,因此这应该不是问题。如果您在someMethod中的某个时刻引用未声明的变量,则会引发NullPointerException

  5. 最后,调用构造函数。此时,所有成员变量都可用,因此它们都可以顺利运行。再次 - 如果有任何未声明的变量,将抛出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()方法的定义,因为编译器会在类文件中定义它。