2014-10-24 1 views
4

В соответствии с SCJP6 (Страница 507) я обнаружил, что переменные экземпляра присваиваются значениям по умолчанию до завершения конструкторов суперкласса, я попробовал пример в режиме отладки, но я увидел, что суперподрядчик работает до того, как переменные экземпляра получат свои значения по умолчанию, объясните это мне?Какой из них запускается первым? значения по умолчанию для переменных экземпляра или суперконструкторы?

Пример я использовал в случае, если кто-то хочет попробовать:

package courseExercise; 

class test { 
    test() { 
     System.out.println("Super Constructor run"); 
    } 
} 

public class Init extends test { 

    private Integer i = 6; 
    private int j = 8; 

    Init(int x) { 
     super(); 
     System.out.println("1-arg const"); 
    } 

    Init() { 
     System.out.println("no-arg const"); 
    } 

    static { 
     System.out.println("1st static init"); 
    } 
    public static int d = 10; 
    { 
     System.out.println("1st instance init"); 
    } 
    { 
     System.out.println("2nd instance init"); 
    } 
    static { 
     System.out.println("2nd static init"); 
    } 

    public static void main(String[] args) { 
     new Init(); 
     new Init(7); 
    } 
} 
+0

Я думаю, потому что вы инициализируете переменные при объявлении. –

+0

, но, как указывает SCJP6, они сказали, что значения по умолчанию назначаются до того, как суперконтрактор будет завершен, даже если инициализация является частью их объявления. – Tarik

+0

«Я видел, что суперподрядчик работает до того, как переменные экземпляра получают значения по умолчанию», как вы это утверждали? (опубликуйте свой журнал) – njzk2

ответ

4

Последовательность инициализации задается в JLS 12.5:

  1. Во-первых, выделяется память для нового объекта
  2. Затем все переменные экземпляра в объекте (включая те, которые определены в этом классе и все его суперклассы) инициализируются значениями по умолчанию
  3. И, наконец, вызывается конструктор.

Соответствующая часть спецификации является:

...

Если не достаточно свободного места, чтобы выделить память для объекта, то создание экземпляра класса завершается преждевременно с OutOfMemoryError. В противном случае все переменные экземпляра в новом объекте, включая объявленные в суперклассах, инициализируются значениями по умолчанию (§4.12.5).

Непосредственно перед ссылкой на вновь созданный объект возвращается как результат, указанный конструктор обрабатывается для инициализации нового объекта, используя следующую процедуру:

...

Это одна из причин, почему вы никогда не должны ссылаться на метод не final от конструктора: этот метод может быть переопределен подклассом, и в этом случае метод будет вызван до того, как подкласс сможет установить состояние, согласно которому метод может необходимость. Рассмотрим следующий пример:

public class Super { 
    private final int superValue; 

    protected Super() { 
    superValue = getSuperValue(); 
    } 

    protected int getSuperValue() { 
    return 1; 
    } 

    @Override 
    public String toString() { 
    return Integer.toString(superValue); 
    } 
} 

public class Sub extends Super { 
    private final int superValueOverride; 

    public Sub(int value) { 
    this.superValueOverride = value; 
    } 

    @Override 
    protected int getSuperValue() { 
    return superValueOverride; 
    } 

    public static void main(String[] args) { 
    Super s = new Sub(2); 
    System.out.println(s); 
    } 
} 

Похоже s.superValue должно быть 2, не так ли? В конце концов, Sub переопределяет getSuperValue(), чтобы вернуть значение superValueOverride, которое инициализируется значением 2. Но этот метод вызывается до того, как будут инициализированы любые поля Sub (кроме значений по умолчанию), поэтому s.superValue фактически равен 0 (по умолчанию значение superValueOverride).

Это даже более странно, потому что superValueOverride является final, и все же оно, кажется, меняет его значение! Это 0, когда Super вызывает getSuperValue(), и только после завершения конструктора Super ему назначено его окончательное значение 2 (или все, что передается конструктору).

+1

Помощник Downvoter для объяснения? – yshavit

+0

thats perfetct, и я понимаю из вашего примера, что переменные присваиваются значениям по умолчанию перед завершением суперконтрактора. но можете ли вы сказать мне, почему для моего примера я не вижу значения «i» и «j» при использовании выражения «watch expression» до завершения суперконтракторов? это только проблема внутри затмения? – Tarik

+0

Возможно, да, может быть, это затмение пытается защитить вас от такого рода замешательства! – yshavit

Смежные вопросы