#java #inheritance #constructor #initialization #overriding
Вопрос:
Я хочу понять, почему результат следующего кода:
public class Base {
private int member1 = 1;
private int member2 = 2;
public Base() {
System.out.println("base ctor");
print();
}
public void print() {
System.out.println(member1 "" member2);
}
}
class Derived extends Base {
private int member3 = 3;
private int member4 = 4;
public Derived() {
System.out.println("derived ctor");
print();
}
public void print() {
System.out.println(member3 "" member4);
}
}
class Test{
public static void main(String[] args) {
Derived d = new Derived();
}
}
является:
base ctor
00
derived ctor
34
- конструктор производного класса неявно вызывает его супер
- конструктор. конструктор super (базовый класс) выводит «базовый ctor»
супер конструктор звонки print()
которая печатает member 1 , member 2
я думал, что member1 и member2 уже инициализирован, потому что, как я думал, что я знаю, когда мы создаем объект порядке вещей статические поля и блоки идут в первую очередь (если его первой загрузки класса), то экземпляр вещи (например, поля и человек) идут по порядку, что означает, что предшествует в порядке код.
Здесь — поля появляются перед конструктором, что означает, что он должен запуститься и уже инициализировать член1 и член2 до того, как он достигнет печати.
Почему он печатается 0 0
?
Это вообще идет в печать Base
или идет в печать Derived
? потому что он вызывается из конструктора Base
, поэтому я его не понимаю.
Спасибо.
Ответ №1:
Вы вызываете print
метод Derived
дважды — один раз во время Base
конструктора и один раз во время Derived
конструктора. Это потому Derived.print()
, что переопределяет Base.print()
.
Так что это ожидание:
super
вызовы конструктораprint()
— который выводитmember 1
,member 2
… неверно. Он вызывает print()
реализацию Derived
, которая печатает member3
и member4
. Они еще не были инициализированы.
Порядок исполнения является:
- Инициализаторы полей базового класса
- Тело конструктора базового класса
- Инициализаторы полей производного класса
- Тело конструктора производного класса
Если вы просто измените два print
своих метода на print1
и print2
(и соответствующим образом измените вызывающий код), он напечатает:
base ctor
12
derived ctor
34
… как вы и ожидали.
Комментарии:
1. Вопрос в том, почему, почему
print()
вызов вBase
конструкторе фактически запускаетprint()
то, что находится вDerived
классе? Я знаю , что объект является anew Derived
, но означает ли это, что даже вызовы из суперконструктора попадут в производную реализацию?2. Потому что вы переопределили
Derived
классе (та же подпись метода, что и в вашемBase
классе). Если вы переименуете методы, как предложил @print1
JonSkeet, иprint2
у вас не возникнет такой проблемы.3. @NoobCoder: Да, используемая реализация метода не меняется в течение срока службы объекта. Это
Derived
объект с самого начала, поэтому любой вызовDerived.print
, даже вBase
конструкторе .4. @JonSkeet этого не знал, спасибо. Что если бы мы объявили объект как
Base obj = new Derived
и вызвали быprint()
базовый конструктор? Мне так странно думать, что если мы вызовемprint()
конструктор класса X (который я считал «святым», потому что это на самом деле создает объект), то фактическоеprint()
, которое будет выполнено, будет другим.5. @NoobCoder: Вам было бы очень легко проверить это самостоятельно, но нет, тип переменной, которой вы назначаете, не имеет значения. Тип объекта, который отвечает за определение используемой реализации метода, остается неизменным на протяжении всего срока его службы.