【问题标题】:Initialization of final fields最终字段的初始化
【发布时间】:2013-12-11 15:52:25
【问题描述】:

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

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();

    }

}

这个 sn-p 的输出是 10。但是当我将变量 i 更改为任何对象时,例如 Integer,输出为 null。但是当我将 i 更改为 static Integer 时,输出是 10 正如预期的那样。

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

谢谢

萝卜

【问题讨论】:

  • 了解类实例化期间的操作顺序..

标签: java initialization field


【解决方案1】:

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

类的静态字段在运行时引用该类时被初始化,这意味着静态字段被初始化类的构造函数被调用之前(在类的super()调用之前)构造函数)。

解释为什么仍然打印 10,当字段类型为 int 时,Java 编译器可能会在编译时内联 final 字段的值。在这种情况下,程序永远不会读取该字段的值,因为编译器优化了代码,使其看起来像 System.out.println(10) 而不是 System.out.println(i)。在这种情况下,Java 编译器未定义内联 final 字段,但是,对于原始字段类型,它可能会这样做,而对于大多数 Object 类型则不太可能。

【讨论】:

    【解决方案2】:

    非静态成员:

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

    当父对象被实例化时,您正在调用 print(),因为它持有将调用的子对象的引用

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

    因为孩子的启蒙在这个阶段还没有完成。整数 i 没有任何值,因此它将打印 null

    静态变量:

    Static data member 在相应的类被引用/调用后立即被初始化,因此它将打印 10.

    【讨论】:

    • 感谢您的回复。我仍然不明白为什么当 i 被声明为 int 时它被初始化,但是当它被声明为 Integer 它没有被初始化。
    【解决方案3】:

    调用父构造函数时不初始化子实例字段

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

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

    因此,当您调用被Child覆盖print() 时,将打印i 的未初始化值。

    静态字段在类初始化时初始化

    类加载过程中发生的类初始化时进行初始化,因此它们的值将被初始化

    【讨论】:

    • 感谢您的回复。还有一个问题:为什么它适用于原始类型 (int) 而不适用于 Object (Integer)?
    • static int 或 static Integer 在这种情况下都应该返回 10。如前所述:静态字段在类初始化时初始化。
    【解决方案4】:

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

    当您声明final Integer i = 10 时会发生什么? 还是int i = 10

    【讨论】:

    • final Integer i = 10 -> null final int i = 10 -> 10 int i = 10 -> 0 Integer i = 10 -> null
    【解决方案5】:

    main 的代码应该是

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

    那么如果你使用int或Integer,则返回10;

    仅使用

    new Child()
    

    那么这个变量没有返回值,新的实例被忽略。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-06
      • 1970-01-01
      • 1970-01-01
      • 2019-11-13
      • 1970-01-01
      相关资源
      最近更新 更多