2012-05-14 2 views
8

Я знаю, что конструкторы объектов Java неявно инициализируют нестатические поля своего экземпляра. Однако я не уверен в том, что это происходит в иерархии классов. Например:Java Constructor and Field Initialization Order

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

Правильно. super(), даже если вы не добавляете его явно, помещается имплицитно в каждый конструктор. Это означает, что сначала вызывается конструктор ShufflePieceSequence, но самое то, что он делает, это позвонить AbstractPieceSequence.

В AbstractPieceSequence вы вызываете метод, определенный в ShufflePieceSequence - который не был инициализирован. На самом деле то, что вы делаете, на самом деле очень тонкая ошибка. Вы никогда не должны вызывать overridable (включая методы abstract) из конструктора. Период. Инструменты AFAIR, такие как и , отмечают это как потенциальную ошибку.

Смотрите также

4

Поля объектов неявно инициализированы ... вам нужно выполнить инициализацию. Может быть, вам нужен ленивый init в этом случае? Как правило, неприятно иметь методы вызова конструктора, которые выполняют нетривиальную работу, обычно это запах, что нечто более сложное, чем оно хочет.

3

Глубина сначала предварительная прогулка.

Андерс делает хорошую точку: Java только инициализирует поля, которые являются родными типами неявно. Любое поле Object является просто ссылкой на Object, и поэтому оно фактически инициализировано, но оно инициализируется null.

0

Порядок вызова конструкторов родительского-Sub класса в случае наследования является то, что конструктор класса Parent всегда запускается сначала, а затем - конструктор класса Child.

Sub class вызывает конструктор базового класса по умолчанию, используя Super(), если явно не задано.