8

我知道 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();
}

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

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

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

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

4

4 回答 4

15

这是正确的。super(),即使您没有显式添加它,也隐含地放置在每个构造函数中。这意味着ShufflePieceSequence首先调用 的构造函数,但它所做的正是调用AbstractPieceSequence.

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

也可以看看

于 2012-05-14T19:34:59.000 回答
4

对象字段未隐式初始化...您需要执行初始化。在这种情况下,也许你需要一个惰性初始化?通常让构造函数调用执行非平凡工作的方法是不愉快的,这通常是一种比它想要的更复杂的气味。

于 2012-05-14T19:30:45.453 回答
3

深度优先,预购步行。

Anders 提出了一个很好的观点:Java 仅隐式初始化本机类型的字段。任何 Object 字段都只是对 Object 的引用,因此它实际上已初始化,但它已初始化为null.

于 2012-05-14T19:31:09.893 回答
0

在继承的情况下,调用父子类的构造函数的顺序是,总是先调用父类的构造函数,然后调用子类的构造函数。

如果没有明确给出,Sub 类默认使用 Super() 调用基类的构造函数。

于 2013-12-09T12:28:33.663 回答