有人可以向我解释这个例子的行为:
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
答案 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()
然后该变量没有返回值,新实例将被忽略。