最终字段的初始化

时间:2013-12-11 15:52:25

标签: java initialization field

有人可以向我解释这个例子的行为:

package test;

public class Test {

    static abstract class Parent{

        public Parent() {
            print();
        }
        public abstract void print();
    }

    static class Child extends Parent{

        protected final int i= 10;

        public Child() {
            super();
        }
        public void print(){
            System.out.println(i);
        }
    }

    public static void main(String[] args) {
        System.out.println("Test");
        new Child();

    }

}

此代码段的输出为 10 。但是当我将变量 i 更改为任何对象(例如Integer)时,输出为 null 。但当我将 i 更改为静态整数时, 10 输出正如预期的那样。

我想在调用任何方法(或构造函数)之前初始化字段,但是这里这种方法只适用于原始类型而不是对象。

由于

的Radim

5 个答案:

答案 0 :(得分:4)

在构造函数中的super()调用之后,直接初始化类的实例字段,无论它们是否为final。但是,super()调用父类的构造函数,该构造函数读取未初始化字段的值。

在运行时引用类时,会初始化类的静态字段,这意味着在调用类的构造函数之前(在super()调用之前,静态字段是在中启动的)班级的建设者)。

当字段类型为int时,仍然打印10的原因是,Java编译器可以在编译时内联最终字段的值。在这种情况下,程序永远不会读取字段的值,因为编译器优化了代码,使其看起来像System.out.println(10)而不是System.out.println(i)。在哪种情况下,Java编译器内联最终字段没有定义,但是,它可能对原始字段类型执行此操作,对大多数对象类型不太可能。

答案 1 :(得分:3)

非静态会员:

new Child()按此顺序触发构造函数链接Parent() - >子()。

当父对象被实例化时,你正在调用print(),因为它保存了它将调用的子对象的引用

public void print(){
            System.out.println(i); 
        }
在这个阶段,由于孩子的启蒙仍未完成。整数i没有任何值,因此会打印null

静态变量:

一旦引用/ envoked相应的类,

Static data member就会被初始化,因此它将被打印  10

答案 2 :(得分:1)

当调用父构造函数

时,不会初始化子实例

这是因为在Parent存在之前Child应存在的逻辑。

首先调用Parent的构造函数,在此期间 Child的所有字段都没有被初始化。

因此,当您print()调用重写Child时,会打印未初始化的i值。

静态字段在类初始化时间

初始化

类加载期间发生的类初始化时间初始化,因此它们将初始化值

答案 3 :(得分:0)

由于字段的最终性质,它在构造函数之前初始化,与变量不同。因此,打印该值。

宣布final Integer i = 10时会发生什么? 还是int i = 10

答案 4 :(得分:0)

主要代码应为

Child child = new Child();
child.print();

然后,如果使用int或Integer,则返回10;

仅使用

new Child()

然后该变量没有返回值,新实例将被忽略。