2012-05-14 77 views
8

我知道Java对象构造函数会隐式地初始化它们的实例的非静态字段。但是,我不确定这是在类层次结构中发生的顺序。例如: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(),但这必须是构造函数体中的第一行(这意味着我仍然没有机会在调用getNextPiece之前初始化包)。

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

回答

15

没错。即使你没有明确地添加它,也会隐含在每个构造函数中。这意味着ShufflePieceSequence的构造函数被称为第一个,但它所做的非常非常称为AbstractPieceSequence

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

4

对象字段不会隐式初始化......您需要执行init。在这种情况下,你可能需要一个懒惰的init?让构造函数调用方法来做非平凡的工作通常是令人不愉快的事情,但它通常是一种比想要的更复杂的东西。

3

深度第一,预购散步。

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

0

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

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