Почему вызывается метод производного класса, а не базового? java
class Super {
public int field = 0;
public int getField() {
return field;
}
}
class Sub extends Super {
public int field = 1;
public int getField() { // используется данный метод
return field;
}
public int getSuperField() {
return super.field;
}
}
public class FieldAccess {
public static void main(String[] args) {
Super sup = new Sub();
System.out.println(sup.field + " " + sup.getField());
Sub sub = new Sub();
System.out.println(sub.field + " " + sub.getField() + " " + sub.getSuperField());
}
}
Вывод:
0 1
1 1 0
Ожидал:
0 0
1 1 0
Ответы (1 шт):
У вас были неправильные ожидания. Так как все методы объекта в Java являются виртуальными по умолчанию (в отличие от C++/C#, где нужно явно использовать ключевое слово virtual
), метод класса-потомка всегда будет виртуально перекрывать неприватный метод базового класса с тем же именем и сигнатурой и вызываться при исполнении кода.
Поэтому, если нужно обеспечить доступ к полю именно в базовом классе при помощи некого геттера, его следовало реализовать именно на уровне базового класса с модификатором final
, чтобы запретить переопределение в потомке:
class Super {
public int field = 0;
public final int getSuperField() {
return field;
}
public int getField() {
return getSuperField();
}
}
Тогда в потомке придётся использовать некий синоним для геттера поля из базового класса:
class Sub extends Super {
public int field = 1;
public int getField() {
return field; // поле класса-потомка
}
// publjc int getSuperField() {} // запрещено переопределять в потомке
public int getBaseField() { // ещё один синоним
return super.field;
}
}
Ну и использование полей с одинаковыми названиями в иерархии классов, тем более открытых (с модификатором доступа public
) -- признак плохого дизайна, нарушающего базовый принцип ООП -- инкапсуляцию.