简体   繁体   English

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

[英]Java Constructor and Field Initialization Order

I aware that Java object constructors implicitly initialize their instance's non-static fields. 我知道Java对象构造函数隐式初始化它们的实例的非静态字段。 However, I'm unsure of the order that this happens in a class hierarchy. 但是,我不确定在类层次结构中发生这种情况的顺序。 For example: 例如:

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

The parent's constructor calls a method in the child class, which throws an exception as the value of List<Shape> bag is currently null. 父的构造函数调用子类中的方法,该方法抛出异常,因为List<Shape> bag值当前为null。

I can define a child constructor and call super(), but that must be the first line in the constructor body (which means I still don't have a chance to initialize bag before getNextPiece is called). 我可以定义一个子构造函数并调用super(),但这必须是构造函数体中的第一行(这意味着我仍然没有机会在getNextPiece之前初始化bag)。

I am missing something obvious. 我错过了一些明显的东西。

That's right. 那就对了。 super() , even if you don't add it explicitly, is placed implictly in every constructor. super() ,即使你没有显式地添加它,也会被隐含地放在每个构造函数中。 This means that the constructor of ShufflePieceSequence is called first, but the very very thing it does is calling AbstractPieceSequence . 这意味着首先调用ShufflePieceSequence的构造函数,但它所做的就是调用AbstractPieceSequence

In AbstractPieceSequence you are calling a method defined in ShufflePieceSequence - which has not been initialized. AbstractPieceSequence您正在调用ShufflePieceSequence定义的方法 - 该方法尚未初始化。 In fact what you are doing is actually a very subtle bug . 事实上,你所做的实际上是一个非常微妙的错误 You should never call overridable (including abstract methods) from constructor. 你永远不应该从构造函数中调用overridable(包括abstract方法)。 Period. 期。 AFAIR tools like and are marking this as a potential bug. 这样的AFAIR工具将此标记为潜在的错误。

See also 也可以看看

Object fields are not implicitly initialized... you need to do the init. 对象字段未被隐式初始化...您需要执行init。 Maybe you need a lazy init in this case? 也许在这种情况下你需要一个懒惰的初始化? Generally unpleasant to have the constructor calling methods that do non-trivial work, it's usually a smell that something is more complex than it wants to be. 让构造函数调用方法做一些非常重要的工作通常是令人不愉快的,它通常是一种比想要的更复杂的气味。

Depth first, a pre-order walk. 深度优先,预订步行。

Anders makes a good point: Java only initializes fields that are native types implicitly. Anders提出了一个很好的观点:Java只隐式初始化本机类型的字段。 Any Object field is merely a reference to Object, and so it in fact initialized, but it's initialized to null . 任何Object字段只是对Object的引用,因此它实际上已初始化,但它被初始化为null

The order of invoking the constructors of Parent-Sub class in case of inheritance is that, the constructor of Parent class always gets invoke first and then the constructor of Child class. 在继承的情况下调用Parent-Sub类的构造函数的顺序是,Parent类的构造函数总是首先调用,然后是Child类的构造函数。

The Sub class calls the constructor of the base class by default using the Super(), if explicitly not given. 如果没有明确地给出,Sub类默认使用Super()调用基类的构造函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM