package com.javarush.task.task15.task1526;
/*
Дебаг, дебаг, и еще раз дебаг
*/
public class Solution {
public static void main(String[] args) {
new B(6);
}
public static class A {
private int f1 = 7;
public A(int f1) {
this.f1 = f1;
initialize();
}
protected void initialize() {
System.out.println(f1);
}
}
public static class B extends A {
protected int f1 = 3;
public B(int f1) {
super(f1);
this.f1 += f1;
initialize();
}
protected void initialize() {
System.out.println(f1);
}
}
}
Почему, когда в 20 строке у метода стоит модификатор protected, тогда результат получается: 0 9?Jonathan Korounets
1 уровень
Задача решена, но не ясно что на самом деле происходит в коде
Решен
Комментарии (8)
- популярные
- новые
- старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Илья ГековMaster
22 ноября 2018, 14:49полезный
Эта задача призвана проиллюстрировать, что инициализация полей и конструкторов довольно запутанный процесс. Но в комменте есть подсказка : "Дебаг, дебаг, и еще раз дебаг". С помощью режима дебага в idea, вы легко можете проследить за каждым действием программы поэтапно и разложить все по полкам не составит труда.
+2
Илья ГековMaster
22 ноября 2018, 14:47решение
В данном коде после вызова в main конструктора класса B (new B(6);) происходит следующее:
1. Начинает выполняться конструктор класса В, в который передается аргумент со значением 6;
2.
вызывается конструктор родительского класса А, в который передается аргумент со значением 6;
3.
присваивается значение 6 полю f1 объекта класса А;
4.
вызывается метод initialize, но так как он переопределен в классе В, который унаследован от А, то вызывается initialize класса В, в котором на экран выводится значение поля f1 класса В, которое на данный момент равно 0, так как еще не было инициализировано никаким значением. (Вывод: 0)
5. Окончено выполнение родительского конструктора, инициализируется поле f1 объекта класса В, присваивается значение 3.
6. К значению f1 класса В прибавляется значение аргумента конструктора - 6, получается f1=9.
7. Вновь происходит вызов метода initialize в конструкторе класса В, на экран выводится уже новое значение f1, которое равно 9.
+12
Илья ГековMaster
22 ноября 2018, 14:56полезный
По поводу того, почему при изменении модификатора доступа в 20-й строке изменяются значения:
- если поставить модификатор private, то класс В просто не увидит, что у А есть такой метод, соответственно initialize() в классе В не будет считаться переопределенным методом и при работе конструктора класса А будет вызван метод класса А.
- если поставить модификатор public, то это не скомпилируется, так как в классе В модификатор метода protected, а при переопределении метода нельзя понижать уровень модификатора.
+9
Jonathan KorounetsРаботает в CyWat Technologies
22 ноября 2018, 17:09
Спасибо! теперь алгоритм понятен. Я думал, что родительский конструктор будет вызывать родительскую версию метода, а не переопределенную. И почему так работает мне остается непонятным... Вроде нелогично так))
0
Jonathan KorounetsРаботает в CyWat Technologies
22 ноября 2018, 17:13
Или тут нужно смотреть на стек? ...раз конструктор родителя был запущен из дочернего, то и метод будет вызван дочернего класса?
0
Илья ГековMaster
22 ноября 2018, 17:23
Можно и так сказать, метод initialize не статический, соответственно он вызывается только через объект класса. Объект у нас создается new B() и от имени этого объекта идет вызов всех методов. Соответственно, при вызове от имени объекта В метода объявленного в классе А сначала проверяется не переопределен ли он классом В.
+5
Илья ГековMaster
22 ноября 2018, 17:44полезный
Можно эксперимента ради поиграться с конструкторами и сделать к примеру так:
Тогда когда мы вызываем конструктор А через super(f1), initialize срабатывает как и раньше тот, что в классе В. Но при создании объекта new A(f1), вызов initialize в конструкторе А приведет уже к вызову initialie из класса А, то есть он уже будет вызван от имени нового объекта А.
+2
Jonathan KorounetsРаботает в CyWat Technologies
22 ноября 2018, 18:45
Супер! Спасибо тебе огромное)))
0