Наследование 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() моего предыдущего примера) в объеме этого класса (т.е. в тело любого из его методов или если оно квалифицировано с именем этого класса) теперь вызовет совершенно другую функцию, требующую квалификации для доступа к статическому методу с тем же именем из родительского класса.

Возможно, ваше замешательство происходит из-за того, что вы предположили, что переписывание влияет на все вызовы метода, даже для объектов базового класса.