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

我知道Java对象构造函数隐式初始化其实例的非静态字段。但是,我不确定这种情况在类层次结构中发生的顺序。例如:

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