Приоритет переопределенного метода в наследнике

Есть, будем говорить, учебный код

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);
        }
    }
}

По условию, надо разобраться, почему вывод "0 9" и как сделать "6 9".

Вопрос вот в чем: почему при вызове initialize() в конструкторе A срабатывает метод класса B? Выходит по умолчанию, если есть выбор, то срабатывает метод наследника? А если сделаем initialize() в А private, то унаследовать метод нельзя, выбора нет и отработает метод в классе A. Так?


Ответы (2 шт):

Автор решения: Drawn Raccoon

Выводится "0 9" из-за порядка инициализации https://ru.stackoverflow.com/a/464038/276430, поля с одинаковыми именами не перегружаются как методы. Получается тут 2 разные переменные, одна в A, другая в B.

Вызывать такие initialize методы всё же лучше после конструирования объекта, т.е. не в конструкторах, а снаружи (тут в main). Также чтобы "проинициализировался" родитель, нужно вызвать в переопределённом методе метод родителя super.initialize();

public class Solution {

    public static void main() throws Exception {
        B b = new B(6);
        b.initialize();
    }


    public static class A {
        private int f1 = 7;

        public A(int f1) {
            this.f1 = f1;
        }

        protected void initialize() {
            System.out.println(f1 + " A");
        }
    }

    public static class B extends A {
        protected int f1 = 3;

        public B(int f1) {
            super(f1);
            this.f1 += f1;
        }

        @Override
        protected void initialize() {
            super.initialize();
            System.out.println(f1 + " B");
        }
    }
}
→ Ссылка
Автор решения: StateItPrimitive

Вам в ответе выше (Drawn Raccoon) отписал почему в текущем варианте не будет работать и как сделать правильно, но имеется еще один вариант решения вашей проблемы (хоть и не очень безопасный, не рекомендуется вызывать методы из конструктора, но я частично закрыл проблему за счет добавления модификатора final на критичные методы):

public class Solution {
    public static void main(String[] args) {
        new B(6);
    }

    static class A {
        private int field;

        A(int field) {
            setField(field);
            initialize();
        }

        final int getField() {
            return field;
        }

        final void setField(int field) {
            this.field = field;
        }

        final void initialize() {
            System.out.println(getField());
        }
    }

    public static class B extends A {
        B(int field) {
            super(field);
            setField(getField() + 3);
            initialize();
        }
    }
}
→ Ссылка