public abstract class Parent {
public String parentField = "dupa";
public Parent(){
init(); // uhh, bad practice to call abstract method in a super constructor
}
protected abstract void init();
}
public class Child extends Parent {
public String childField = null; // assigning null is unnecessary, another bad practice
@Override
protected void init(){
childField = "initialized";
System.out.println("After init(): " + childField);
}
}
...
Child child = new Child(); // OUTPUT: After init(): initialized
System.out.println("After all: " + child.childField); // OUTPUT: After all: null
我在调用new Child();
时发现执行顺序是什么:
我知道这个例子充满了不良做法。但是,我的直观顺序是:字段初始化(从父项到子项),然后是构造函数(从父项到子项)。
这种初始化顺序的目的是什么? 为什么字段初始值设定项在首次使用之前未执行? 如果该字段尚未初始化,那么为什么允许使用它呢?
答案 0 :(得分:2)
让我解释一下构建新对象的“直观”顺序:
嗯,这不太合理,因为子字段的初始化可能依赖于父级。
当构造函数返回时,可以将对象视为“正确初始化”。同意?
不要使用Parent
和Child
,而是使用Box
和TreasureBox
。要构建TreasureBox
,首先要制作Box
。创建框后,您可以为其添加不同的装饰,使其看起来非常华丽和酷炫,您还可以添加锁或其他内容。
请参阅?这里的订单?在初始化子代之前首先正确初始化父代表是最有意义的,这意味着子类的任何初始化必须在父代的构造函数返回之后发生。这正是Java正在做的事情。
孩子的字段可以取决于父母的字段。要锁定TreasureBox
,您需要找到方框的正面,并将其放在那里。如果尚未创建盒子的正面,你怎么能锁定它?
这里有一些代码来澄清我的意思:
class Parent {
public String parentField;
public Parent(){
parentField = "Hello";
}
}
class Child extends Parent {
public int childField = parentField.length();
}
如果Java使用您的“直观”订单,则会抛出NPE。