Java构造函数和字段初始化顺序
我知道Java对象构造函数隐式初始化其实例的非静态字段。但是,我不确定这种情况在类层次结构中发生的顺序。例如:Java构造函数和字段初始化顺序,java,inheritance,initialization,pmd,findbugs,Java,Inheritance,Initialization,Pmd,Findbugs,我知道Java对象构造函数隐式初始化其实例的非静态字段。但是,我不确定这种情况在类层次结构中发生的顺序。例如: abstract public class AbstractPieceSequence implements PieceSequence { private Tetromino current; private Tetromino preview; public AbstractPieceSequence() { advance();
abstract public class AbstractPieceSequence implements PieceSequence
{
private Tetromino current;
private Tetromino preview;
public AbstractPieceSequence()
{
advance();
}
@Override
public final void advance()
{
if (preview == null) {
current = getNextPiece();
preview = getNextPiece();
} else {
current = preview;
preview = getNextPiece();
}
}
abstract protected Tetromino getNextPiece();
}
公共类ShufflePieceSequence扩展了AbstractPieceSequence
{
私有列表包=新的LinkedList();
@凌驾
受保护的Tetromino getNextPiece()
{
如果(袋大小()==0){
集合.addAll(包,Shape.I,Shape.J,Shape.L,Shape.O,Shape.S,Shape.T,Shape.Z);
}
返回Tetromino.tetrominoes.get(bag.remove(0));
}
}
父类的构造函数调用子类中的一个方法,该方法在List bag
的值当前为null时引发异常
我可以定义一个子构造函数并调用super(),但那必须是构造函数主体中的第一行(这意味着在调用getNextPiece
之前,我仍然没有机会初始化bag)
我遗漏了一些明显的内容。对象字段未隐式初始化。。。你需要进行初始化。在这种情况下,也许你需要一个懒惰的init?通常情况下,让构造函数调用方法来完成非琐碎的工作是令人不愉快的,这通常是一种感觉,某种东西比它想要的更复杂。深度优先,一种预先排序的行走 Anders提出了一个很好的观点:Java只隐式初始化本机类型的字段。任何对象字段都只是对对象的引用,因此它实际上已初始化,但它已初始化为
null
没错super()
,即使您没有显式地添加它,也会隐式地放置在每个构造函数中。这意味着首先调用ShufflePieceSequence
的构造函数,但它所做的事情就是调用AbstractPieceSequence
在AbstractPieceSequence
中,您正在调用ShufflePieceSequence
中定义的尚未初始化的方法。事实上,您所做的实际上是一个非常微妙的bug。永远不要从构造函数调用可重写(包括抽象方法)。时期AFAIR工具(如和)正在将此标记为一个潜在错误
另见
继承时调用父类子类构造函数的顺序是,父类的构造函数总是先得到invoke,然后是子类的构造函数
默认情况下,如果没有明确给出,子类将使用Super()调用基类的构造函数
public class ShufflePieceSequence extends AbstractPieceSequence
{
private List<Shape> bag = new LinkedList<Shape>();
@Override
protected Tetromino getNextPiece()
{
if (bag.size() == 0) {
Collections.addAll(bag, Shape.I, Shape.J, Shape.L, Shape.O, Shape.S, Shape.T, Shape.Z);
}
return Tetromino.tetrominoes.get(bag.remove(0));
}
}