Java构造函数和字段初始化顺序

efr*_*itz 8 java inheritance initialization

我知道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();
}
Run Code Online (Sandbox Code Playgroud)
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));
    }
}
Run Code Online (Sandbox Code Playgroud)

父的构造函数调用子类中的方法,该方法抛出异常,因为List<Shape> bag当前值为null.

我可以定义一个子构造函数并调用super(),但这必须是构造函数体中的第一行(这意味着在getNextPiece调用之前我仍然没有机会初始化bag ).

我错过了一些明显的东西.

Tom*_*icz 15

那就对了.super()即使你没有明确地添加它,也会隐含地放在每个构造函数中.这意味着ShufflePieceSequence首先调用构造函数,但它所做的就是调用AbstractPieceSequence.

AbstractPieceSequence您调用的方法中ShufflePieceSequence- 尚未初始化.事实上,你所做的实际上是一个非常微妙的bug.你永远不应该abstract从构造函数调用overridable(包括方法).期.像这样的AFAIR工具将此标记为潜在的错误.

也可以看看