Наследование Java: перезаписанные или скрытые методы
Когда класс расширяет другой, он наследует все методы и переменные суперкласса. Оба метода и переменные могут использоваться по-разному в подклассе, если вы определяете его по-разному в подклассе с той же сигнатурой.
Теперь Oracle отличается между переписыванием и скрытием (http://docs.oracle.com/javase/tutorial/java/IandI/override.html).
В нем говорится, что метод экземпляра перезаписывает свой метод суперкласса, а метод класса скрывает его.
"Различие между скрытием и переопределением имеет важные последствия. Версия переопределенного метода, который вызывается, является таковой в подклассе. Версия скрытого метода, который вызывается, зависит от того, вызвана ли она из суперкласса или подкласса".
Предположим, что у меня есть 2 класса Да и Возможно. Да простирается Может быть.
Может быть, String a.
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 знает
лучше, поэтому я думаю, что я просто не понял эту статью.
Нельзя сказать, что когда я вызываю метод экземпляра из объекта суперкласса, он использует перезаписанный метод.
Поэтому я не понимаю, почему отличить переписывание и скрытие!
Может кто-нибудь помочь?
Изменить; Введенный код вместо описания классов!
Ответы
Ответ 1
Статические методы вообще не могут быть переопределены. Они не называются полиморфно, поскольку они не действуют на экземпляр класса, а на самом классе.
Если вы вызываете 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
).
Ответ 2
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());
}
}
OUTPUT будет: - (метод статического метода против экземпляра)
р
с
с
зр
Южная Каролина
зр
Ответ 3
Возьмем следующий пример, основанный на вашем примере:
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()
моего предыдущего примера) в объеме этого класса (т.е. в тело любого из его методов или если оно квалифицировано с именем этого класса) теперь вызовет совершенно другую функцию, требующую квалификации для доступа к статическому методу с тем же именем из родительского класса.
Возможно, ваше замешательство происходит из-за того, что вы предположили, что переписывание влияет на все вызовы метода, даже для объектов базового класса.