Инициализация в полиморфизме переменных
Предположим, что у вас есть следующий код
class A {
int i = 4;
A() {
print();
}
void print () {
System.out.println("A");
}
}
class B extends A {
int i = 2; //"this line"
public static void main(String[] args){
A a = new B();
a.print();
}
void print () {
System.out.println(i);
}
}
это напечатает 0 2
Теперь, если вы удалите строку с надписью "this line",
код будет печатать 4 4
- Я понимаю, что если бы не было int я = 2; line,
A a = new B();
вызовет класс A, инициализирует я как 4, конструктор вызова,
который дает управление методу print()
в class B
и, наконец, печатает 4.
a.print()
вызовет метод print()
в классе B, потому что методы будут привязываться во время выполнения, что также будет использовать значение, определенное в классе A, 4.
(Конечно, если в моих рассуждениях есть какая-то ошибка, дайте мне знать)
- Однако я не понимаю, есть ли int я = 2.
почему, если вы вставляете код, первая часть (создающий объект) будет все внезапно печатать 0 вместо 4? Почему это не инициализирует переменную как я = 4, а вместо этого назначает значение по умолчанию?
Ответы
Ответ 1
Это комбинация нескольких действий в Java.
- Переопределение метода
- Тенерирование переменных экземпляра
- порядок конструкторов
Я просто просмотрю, что произошло в вашем коде, и посмотрите, понимаете ли вы.
Ваш код концептуально выглядит следующим образом (пропустить main()):
class A {
int i = 0; // default value
A() {
A::i = 4; // originally in initialization statement
print();
}
void print () {
System.out.println("A");
}
}
class B extends A {
int i = 0; // Remember this shadows A::i
public B() {
super();
B::i = 2;
}
void print () {
System.out.println(i);
}
}
Итак, когда в исходном main()
, вы вызвали A a = new B();
, он создает B
, для которого это происходит:
-
A::i
и B::i
все находятся по умолчанию 0
- super(), что означает, что конструктор называется
-
A::i
установлено значение 4
-
print()
. Из-за позднего связывания он привязан к B::print()
-
B::print()
пытается распечатать B::i
, который по-прежнему 0
-
B::i
установлено значение 2
Затем, когда вы вызываете a.print()
в main()
, он ограничен B::print()
, который печатает B::i
(на данный момент это 2).
Следовательно, результат вы видите
Ответ 2
Все переменные экземпляра нового объекта, в том числе объявленные в суперклассах, инициализируются значениями по умолчанию - JLS 12.5
Следовательно, ваша переменная B::i
будет инициализирована на 0. Конструктор в B будет выглядеть следующим образом:
B() {
super();
i = 2;
}
Поэтому, когда вы вызываете
A a = new B();
Конструктор в вызовет метод print
в B, который напечатает i
в классе B, который равен 0.
Ответ 3
В вашем случае класс B объявление "i" скрывает объявление "i" в A, а все ссылки на "i" в дочернем классе относятся к B.i, а не к A.i.
Итак, то, что вы видите в A.i, является значением по умолчанию для любого атрибута int в java, который равен нулю.
Переменные экземпляра Java нельзя переопределять в подклассе.
Вы хотите попробовать это для уточнения.
class B extends A {
int i = 2; //"this line"
public static void main(String[] args){
B b = new B();
A a = b;
System.out.println("a.i is " + a.i);
System.out.println("b.i is " + b.i);
}
void print () {
System.out.println(i);
}
}
Ouput:
a.i is 4
b.i is 2