Ведущий вопрос легко ответить:
Является ли это обычная практика, чтобы всегда использовать супер для вызова методов выхода из суперкласса, даже когда я не перекрывая метод?
Нет, это не обычная практика. Наоборот, его опасно запутывает. Вы обычно вызываете методы, потому что основной точкой наследования является разрешить классам переопределять методы для изменения/расширения их поведения. Обычно вам не важно, на каком уровне фактически реализован метод.
Очевидное исключение, когда вы сделать переопределить метод себя, и вы хотите/должны функциональность родителей.
Теперь к опасно запутанным часть явного вызова супер:
public class CallSuper {
static class Parent {
public void foo() {
System.out.println("Parent.foo");
}
/**
* Calls foo to do the main work
*/
public void bar() {
System.out.print
foo();
}
}
static class Child extends Parent {
public void foo() {
System.out.println("Child.foo");
}
public void bar() {
super.foo();
}
}
static class GrandChild extends Child {
public void foo() {
System.out.println("GrandChild.foo");
}
}
public static void main(String[] args) {
Parent p = new Parent();
Parent c = new Child();
Parent g = new GrandChild();
System.out.print("Parent.foo() = ");
p.foo();
System.out.print("Child.foo() = ");
c.foo();
System.out.print("GrandChild.foo() = ");
g.foo();
System.out.print("Parent.bar() = ");
p.bar();
System.out.print("Child.bar() = ");
c.bar();
System.out.print("GrandChild.bar() = ");
g.bar();
}
}
Если запустить этот пример выведет (добавлены номера строк для ясности):
1 Parent.foo() = Parent.foo
2 Child.foo() = Child.foo
3 GrandChild.foo() = GrandChild.foo
4 Parent.bar() = Parent.foo
5 Child.bar() = Parent.foo
6 GrandChild.bar() = Parent.foo
Первые четыре строки не удивительны, мы получаем то, что foo реализует на каждом уровне, соответственно, бар Parents, вызывающий его foo. Он начинает становиться нечетным в строке 5. Ребенок обходит свое собственное переопределение foo, вызывая super.bar(), поэтому, когда его foo() специализирован, bar() не является. В строке 6 вы видите, что GrandChild наследует эту странность от Child, поэтому несколько невинно выглядящий super.foo() в детском баре теперь нарушил ожидания GrandChild, что его переопределение foo() также эффективно для всех bar().
Теперь, если вы представляете себе foo() и bar() на самом деле что-то делает полезно и что они имеют значимые отношения друг с другом, например. вы вынуждены верить (либо документацией Родителя, либо просто здравым смыслом), что переопределение foo() также изменит поведение bar(). Ребенок «супер» нарушает это.
Как правило, если вы видите вызов «super.x()» где-то вне фактического переопределить «x()», то, вероятно, это произойдет.
Это правда, но, похоже, это не относится к случаю, который задал ОП. В этом примере предполагается, что ОП задает вопрос о вызове метода super из дочернего метода. Этот ответ касается обхода реализации ребенка от вызова кода. – Brick
@ Брат, ты не понимаешь моего ответа. –
Следует отметить, что если вы не собираетесь переопределять какой-либо метод (и управлять суперклассом), гораздо лучше объявить его «final». В любом случае не используйте 'super' только для повышения производительности. Если JVM видит, что метод не переопределен, вызов 'method()' в горячем коде станет таким же быстрым, как 'super.method()'. –