2013-08-25 3 views
1
class Alpha 
{ 
     String name = "Alpha"; 
     Alpha() 
     { 
      print(); 
     } 
     void print() 
     { 
      System.out.println("Alpha Constructor"); 
     } 
} 
class Beta extends Alpha 
{ 
     int i = 5; 
     String name = "Beta"; 
     public static void main(String[] args) 
     { 
      Alpha a = new Beta(); 
      a.print();//Line1 executes Beta constructor 
      System.out.println(a.name);//Line 2 displays Alpha instance variable 
     } 
     void print() 
     { 
      System.out.println(i); 
     } 
} 

Эта программа успешно компилируется и отображает следующий результат.Конструктор - исполнительный код

0 
5 
Alpha 

Вопросы

а) Я не понимаю, почему конструктор Альфов не получил казнен первым.

Я считаю, что «super()» будет называться неявно каждым дочерним конструктором первым ... right?.

b) Если конструктор Beta уже выполнен, то почему напечатан «5»? (Вторая строка в выводе)

Третья линию я вроде понимаю (т.е. собственные переменная Альфа будет отображаться, поскольку литье еще не сделана на «а» переменный экземпляр)

+1

Откуда взялось это '0'? м? –

+0

'0' - результат первого запуска' print', где 'i' еще не отменено. Оба конструктора называют 'print', но в то время, когда' Alpha'constructor вызывает 'print''i', инициализатор экземпляра еще не инициализирован. – Sebastian

ответ

4
class Alpha 
{ 
     String name = "Alpha"; 
     Alpha() 
     { 
      print(); 

Это один здесь на самом деле вызывает Beta.print(), потому что это @Override s Alpha.print(). Поскольку базовый класс конструкторы называют первым, то Beta часть еще не был инициализирован здесь, таким образом, он печатает 0, так как ...

 } 
     void print() 
     { 
      System.out.println("Alpha Constructor"); 
     } 
} 
class Beta extends Alpha 
{ 
     int i = 5; 

эта строка кода еще не был выполнен. Инициализация внутри тела класса выполняется после конструктора суперкласса (super()), но перед телом конструктора того же класса.

 String name = "Beta"; 
     public static void main(String[] args) 
     { 
      Alpha a = new Beta(); 
      a.print();//Line1 executes Beta constructor 

Здесь он напечатает 5, в качестве инициализации Beta (a) завершена.

  System.out.println(a.name);//Line 2 displays Alpha instance variable 
     } 

И это говорит метод фактически неоспоримым называется:

 void print() 
     { 
      System.out.println(i); 
     } 
} 

Init/Призывание заказ:

  • Object.Object()
  • Alpha.<instance vars>
  • Alpha.<constructor body>
    • Beta.print() который отменяет Alpha.print() (печатает Beta.i, который по-прежнему 0 (по умолчанию))
  • Beta.<instance vars> (Здесь Beta.i будет инициализирован до 5)
  • Beta.<constructor body>
  • Beta.print() который перекрывает Alpha.print() (отпечатки Beta.i, который, наконец, равен 5, поскольку завершение инициализации завершено)
+0

Отличное объяснение Спасибо – UnderDog

+0

Добро пожаловать! – Sam

5

Вы совершаете два «тяжкие преступления» здесь:

  1. вызов переопределяемого метода из конструктора;
  2. Объявление переменной экземпляра в подклассе с тем же именем, что и в суперклассе.

Обе идиомы приводят к удивительному поведению. В частности, 1. приводит к выходу Beta#print из конструктора Alpha, что приводит к печати 0, поскольку вы вызываете print на унифицированном экземпляре Beta. И это происходит точно , потому что суперконструктор работает перед конструктором подкласса.

Таким образом, вызов переопределенного метода из конструктора приводит к нежелательному изменению порядка выполнения: управление передается из конструктора суперкласса в метод подкласса.

Что касается вашего вопроса о том, почему 5 напечатан: a.print(), в отличие от a.name, это метод вызова, подлежащего динамической отправке. Поэтому независимо от объявленного типа a (который равен Alpha) вызывается метод Beta#print (то же самое происходит в конструкторе Alpha, но перед инициализацией переменной i).

0
  • Конструктор Alpha выполняет кадровые работы в первую очередь. Если вы положите System.out.println("Alpha Ctr"); в Alpha() метод, вы заметите, что печатается Alpha Ctr.
  • Дело в том, что вы переопределили метод print() в классе детей Beta. Поэтому Beta#print() выполняется вместо Alpha#print().

Если изменить Beta#print() немного такое поведение будет более ясно:

void print() { 
    System.out.println(name + ": " + i); 
} 

Это теперь будет печатать:

null: 0 
Beta: 5 
Alpha 

Здесь печатает null: 0, поскольку переменная name & i являются инициализирован на время построения родительского класса Alpha.

1

Я не понимаю, почему конструктор Alpha не был выполнен в первую очередь.

Это было выполнено в первую очередь. Я не знаю, что заставило вас думать, что нет. Возможно, выход 0. Это связано с тем, что вы вызывали переопределенный метод в конструкторе, который вызовет метод print() в классе Beta. Теперь, поскольку в этот момент переменная i еще не была инициализирована, она будет печатать 0. См. this answer для более подробной информации. Я также написал blog post по этой теме.

Я считаю, что «super()» будет вызвано неявно каждым дочерним конструктором первым ... правильно?

Не всегда. Когда вы связываете конструктор того же класса с помощью this(), super() не будет добавлен. Конструктор суперкласса супер-класса будет привязан.

Если конструктор Beta уже выполнен, то почему напечатан «5»?

Почему бы и нет? Бета-конструктор будет инициализировать i с помощью 5. Инициализация, которую вы делаете в точке объявления, перемещается в каждый конструктор вашего класса компилятором после инструкции super() или this(), что бы там ни было.

+0

Приятно видеть ваш блог в первый раз .... Вы должны написать о regex stuffs в своем блоге .... –

+1

@LolCoder. Конечно. Как позволяет время, и что более важно, когда я думаю, что у меня есть что-то интересное для написания, выведет его точно. Спасибо :) –