Наследование Java: перезаписанные или скрытые методы
Когда класс расширяет другой, он наследует все методы и переменные суперкласса. И методы, и переменные могут использоваться по-разному в подклассе, если вы определяете его по-разному в подклассе с одной и той же сигнатурой. Теперь Oracle проводит различие между перезаписью и сокрытием (http://docs.oracle.com/javase/tutorial/java/IandI/override.html). Он говорит, что метод экземпляра перезаписывает метод своего суперкласса, а метод класса скрывает его. "Различие между сокрытием и переопределением имеет важные последствия. Версия переопределенного метода, который вызывается, является версией в подклассе. Версия скрытого метода, который вызывается, зависит от того, вызывается ли он из суперкласса или подкласса".
Допустим, у меня есть 2 класса, да и может быть. Да расширяет Может быть, имеет строку.
class Maybe {
String a;
public static void printOut() {
System.out.println("Maybe");
}
public void printAndSet() {
a = "Maybe";
System.out.println(a);
}
}
class Yes extends Maybe {
public static void printOut() {
System.out.println("Yes");
}
pubilc void printAndSet() {
a = "Yes";
}
}
class Print{
public static void mail(String[] args) {
Maybe m = new Maybe();
Yes y = new Yes();
Maybe.printOut();
Yes.printOut();
m.printAndSet();
y.printAndSet();
}
И я говорю: он распечатает, может быть, да, может быть да
Но после прочтения статьи об Oracle я подумал, что ее нужно будет распечатать:
yes
yes
maybe
yes
Потому что метод экземпляра перезаписывает свой метод суперкласса.
Я совершенно уверен, что я прав с выводом, но я также уверен, что Oracle знает лучше, так что я думаю, что просто не понял статью. Не может быть правдой, что когда я вызываю метод экземпляра из объекта суперкласса, он использует перезаписанный метод. Поэтому я не понимаю, почему нужно различать перезапись и сокрытие! Может кто-нибудь помочь?
Редактировать; Вставлен код вместо описания классов!
3 ответа
Статические методы не могут быть переопределены вообще. Они не вызываются полиморфно, поскольку они действуют не на экземпляр класса, а на сам класс.
Если вы позвоните Maybe.printOut()
, это будет называть статическим printOut()
метод, определенный в Maybe
, Тот факт, что есть также метод printOut()
определяется в Yes
не имеет значения: эти два метода не имеют ничего общего, кроме их имени.
Обратите внимание, что вы можете подтвердить или подтвердить свои сомнения, просто написав программу и выполнив ее.
Проблема со скрытыми методами возникает только тогда, когда вы начинаете вызывать статические методы для экземпляра объекта. Это очень плохая практика, и ее никогда не следует делать. Если вы не уважаете это правило и имеете следующее:
Maybe m = new Maybe();
Maybe y = new Yes();
m.printOut(); // DON'T DO THAT: it should be Maybe.printOut();
y.printOut(); // DON'T DO THAT: it should be Maybe.printOut() or Yes.printOut();
результат будет maybe maybe
потому что в случае статических методов учитывается не конкретный тип объектов (Maybe
а также Yes
), но их объявленный тип (Maybe
а также Maybe
).
public class Parent {
public String test(){
return "p";
}
public static String testStatic(){
return "sp";
}
}
public class Child extends Parent {
public String test(){
return "c";
}
public static String testStatic(){
return "sc";
}
}
public class Demo{
public static void main(String[] args) {
Parent p =new Parent();
Child c = new Child();
Parent pc = new Child();
System.out.println(p.test());
System.out.println(c.test());
System.out.println(pc.test());
//Although this is not the correct way of calling static methods
System.out.println(p.testStatic());
System.out.println(c.testStatic());
System.out.println(pc.testStatic());
}
}
ВЫВОД будет: - (статический метод против метода экземпляра)
p c c sp sc sp
Возьмите следующий пример, основанный на вашем примере:
public class SO11720216 {
static class Maybe {
public static void hidden() { System.out.println("static maybe"); }
public void overwritten() { System.out.println("instance maybe"); }
public void inherited() { hidden(); }
public void called() { overwritten(); inherited(); }
}
static class Yes extends Maybe {
public static void hidden() { System.out.println("static yes"); }
public void overwritten() { System.out.println("instance yes"); }
}
public static void main(String[] args) {
Maybe m = new Maybe();
Yes y = new Yes();
m.called(); /* prints:
instance maybe
static maybe
*/
y.called(); /* prints:
instance yes
static maybe
*/
Yes.hidden(); /* prints: static yes */
y.hidden(); /* bad style! prints: static yes */
}
}
Призыв к overwritten
будет перезаписан каждым производным классом. Таким образом, каждый метод будет использовать реализацию, принадлежащую текущему объекту. С другой стороны, призыв к hidden
всегда будет использовать реализацию определяющего класса. следовательно Maybe.called
всегда буду звонить Maybe.hidden
, и никогда Yes.hidden
, Звонить Yes.hidden
, вам придется сделать это из метода в Yes
или используя квалифицированное имя.
Чтобы выразить это по-другому:
- Перезапись метода означает, что всякий раз, когда метод вызывается для объекта производного класса, вызывается новая реализация.
- Скрыть метод означает, что безусловный вызов этого имени (например,
hidden()
позвонить вinherited()
метод моего приведенного выше примера) в области действия этого класса (т.е. в теле любого из его методов или при наличии имени этого класса) теперь будет вызывать совершенно другую функцию, требующую квалификации для доступа к статическому методу то же имя из родительского класса.
Возможно, ваше замешательство связано с тем, что вы предполагали, что перезапись повлияет на все вызовы метода, даже для объектов базового класса.