Überschreiben oder Ausblenden von Java - verwirrt

84

Ich bin verwirrt darüber, wie sich das Überschreiben vom Verstecken in Java unterscheidet. Kann jemand mehr Details darüber geben, wie sich diese unterscheiden? Ich habe das Java-Tutorial gelesen, aber der Beispielcode hat mich immer noch verwirrt.

Um es klarer zu machen, verstehe ich das Überschreiben gut. Mein Problem ist, dass ich nicht sehe, wie sich das Verstecken unterscheidet, außer dass sich eines auf Instanzebene befindet, während sich das andere auf Klassenebene befindet.

Betrachten Sie den Java-Tutorial-Code:

public class Animal {
    public static void testClassMethod() {
        System.out.println("Class" + " method in Animal.");
    }
    public void testInstanceMethod() {
        System.out.println("Instance " + " method in Animal.");
    }
}

Dann haben wir eine Unterklasse Cat:

public class Cat extends Animal {
    public static void testClassMethod() {
        System.out.println("The class method" + " in Cat.");
    }
    public void testInstanceMethod() {
        System.out.println("The instance method" + " in Cat.");
    }

    public static void main(String[] args) {
        Cat myCat = new Cat();
        Animal myAnimal = myCat;
        Animal.testClassMethod();
        myAnimal.testInstanceMethod();
    }
}

Dann sagen sie:

Die Ausgabe dieses Programms lautet wie folgt:

Klassenmethode in Tier.

Die Instanzmethode in Cat.

Für mich ist die Tatsache, dass das Aufrufen einer Klassenmethode testClassMethod()direkt von der AnimalKlasse aus die Methode in der Klasse ausführt, Animalziemlich offensichtlich, nichts Besonderes. Dann rufen sie das testInstanceMethod()von einem Verweis auf auf myCat, was wiederum ziemlich offensichtlich ist, dass die dann ausgeführte Methode diejenige in der Instanz von ist Cat.

Soweit ich weiß, verhält sich das Ausblenden von Anrufen wie das Überschreiben. Warum also diese Unterscheidung treffen? Wenn ich diesen Code mit den oben genannten Klassen ausführe:

Cat.testClassMethod();

Ich werde bekommen: Die Klassenmethode in Cat. Aber wenn ich das testClassMethod()von Cat entferne , bekomme ich: Die Klassenmethode in Animal.

Was mir zeigt, dass das Schreiben einer statischen Methode mit derselben Signatur wie im übergeordneten Element in einer Unterklasse so ziemlich eine Überschreibung bewirkt.

Hoffentlich mache ich klar, wo ich verwirrt bin und jemand kann etwas Licht ins Dunkel bringen. Vielen Dank im Voraus!

Lostlinkpr
quelle

Antworten:

102

Das Überschreiben unterstützt grundsätzlich die späte Bindung. Daher wird zur Laufzeit entschieden, welche Methode aufgerufen wird. Es ist für nicht statische Methoden.

Das Ausblenden gilt für alle anderen Mitglieder (statische Methoden, Instanzmitglieder, statische Mitglieder). Es basiert auf der frühen Bindung. Genauer gesagt wird die Methode oder das Mitglied, das aufgerufen oder verwendet werden soll, während der Kompilierungszeit festgelegt.

In Ihrem Beispiel ist der erste Aufruf Animal.testClassMethod()ein Aufruf einer staticMethode, daher ist es ziemlich sicher, welche Methode aufgerufen wird.

Im zweiten Aufruf rufen myAnimal.testInstanceMethod()Sie eine nicht statische Methode auf. Dies nennen Sie Laufzeitpolymorphismus. Erst zur Laufzeit wird entschieden, welche Methode aufgerufen werden soll.

Weitere Informationen finden Sie unter Überschreiben gegen Verstecken .

Kazekage Gaara
quelle
3
Vielen Dank für die schnelle Antwort, dies verdeutlicht es! Ich habe festgestellt, dass im JavaRanch-Beispiel die Variable zum Aufrufen der Klassenmethode verwendet wurde, anstatt die Klasse direkt zu verwenden, was das Verständnis erleichtert. Ich denke, im Java-Tutorial haben sie die Klasse direkt verwendet, da die Verwendung einer Instanz zum Aufrufen einer statischen Methode wahrscheinlich keine gute Praxis ist, aber sie hätten myAnimal.testClassMethod () anstelle von Animal.testClassMethod () verwenden sollen .
Lostlinkpr
+1 für die Fähigkeit, es richtig in Worte zu fassen, anstatt mit gutem Beispiel! :)
WhyNotHugo
@Kazekage Gaara Gibt es einen Unterschied zwischen Überladen und Verstecken?
gstackoverflow
1
Ich stimme der Antwort natürlich zu, aber wie wäre es private methods? Sie können es nicht sein, overriddenda die Unterklasse nichts über ihre Existenz weiß. Deshalb könnten sie es hiddenstattdessen sein.
Paschalis
Hervorragende Antwort! Obwohl Sie das Beispiel der Vollständigkeit halber bei coderanch hinzufügen könnten :)
Shubham Mittal
18

Statische Methoden werden ausgeblendet, nicht statische Methoden werden überschrieben. Der Unterschied ist bemerkenswert, wenn Aufrufe nicht als "etwas ()" oder "this.something ()" qualifiziert sind.

Ich kann es nicht wirklich auf Worte fassen, also hier ein Beispiel:

public class Animal {

    public static void something() {
        System.out.println("animal.something");
    }

    public void eat() {
        System.out.println("animal.eat");
    }

    public Animal() {
        // This will always call Animal.something(), since it can't be overriden, because it is static.
        something();
        // This will call the eat() defined in overriding classes.
        eat();
    }

}


public class Dog extends Animal {

    public static void something() {
        // This method merely hides Animal.something(), making it uncallable, but does not override it, or alter calls to it in any way.
        System.out.println("dog.something");
    }

    public void eat() {
        // This method overrides eat(), and will affect calls to eat()
        System.out.println("dog.eat");
    }

    public Dog() {
        super();
    }

    public static void main(String[] args) {
        new Dog();
    }

}

AUSGABE:

animal.something
dog.eat
WhyNotHugo
quelle
1
ok, was würde dann passieren, wenn ich "dog husky = new dog ()" nenne? und call husky.Animal();wird es animal.something oder dog.something drucken ? Ich denke, es ist FALSCH zu sagen, dass dies immer Animal.something ()
amarnath harish
13

Dies ist der Unterschied zwischen Überschreibungen und Verstecken.

  1. Wenn sowohl die Methode in der übergeordneten Klasse als auch die untergeordnete Klasse eine Instanzmethode sind, werden Überschreibungen aufgerufen.
  2. Wenn sowohl die Methode in der übergeordneten als auch in der untergeordneten Klasse statische Methoden sind, wird dies als Ausblenden bezeichnet.
  3. Eine Methode kann im übergeordneten Element und im untergeordneten Element nicht statisch sein. und umgekehrt.

Geben Sie hier die Bildbeschreibung ein

Rudy
quelle
3
Sie haben diese Tabelle direkt aus dem Tutorial ausgeschnitten und eingefügt, von dem das OP sagte, dass es ihm nicht geholfen hat, es zu verstehen.
Wolfcastle
Die Tabelle macht sehr deutlich, in den Beispielen wurden nicht alle Fälle berücksichtigt.
Tutak
3

Wenn ich Ihre Frage richtig verstehe, lautet die Antwort "Sie überschreiben bereits".

"Was mir zeigt, dass das Schreiben einer statischen Methode mit demselben Namen wie im übergeordneten Element in einer Unterklasse so ziemlich eine Überschreibung bewirkt."

Wenn Sie eine Methode in eine Unterklasse mit genau demselben Namen wie eine Methode in einer Oberklasse schreiben, wird die Methode der Oberklasse überschrieben. Die Annotation @Override ist nicht erforderlich, um eine Methode zu überschreiben. Dies macht Ihren Code jedoch lesbarer und zwingt den Compiler zu überprüfen, ob Sie tatsächlich eine Methode überschreiben (und beispielsweise die Unterklassenmethode nicht falsch geschrieben haben).

thagorn
quelle
1
Diese Antwort behandelt Instanz- und statische Methoden in Bezug auf das Überschreiben / Ausblenden nicht.
Paul Bellora
3

Das Überschreiben erfolgt nur mit Instanzmethoden. Wenn der Typ der Referenzvariablen Animal und das Objekt Cat ist, wird die Instanzmethode von Cat aufgerufen (dies wird überschrieben). Für dasselbe acat-Objekt wird die Klassenmethode Animal verwendet.

public static void main(String[] args) {
    Animal acat = new Cat();
    acat.testInstanceMethod();
    acat.testClassMethod();

}

Ausgabe ist:

The instance method in Cat.
Class method in Animal.
Yiannis
quelle
2
public class First {

    public void Overriding(int i) {  /* will be overridden in class Second */ }

    public static void Hiding(int i) {  /* will be hidden in class Second
                                           because it's static */ }
}


public class Second extends First {

    public void Overriding(int i) {  /* overridden here */  }

    public static void Hiding(int i) {  /* hides method in class First
                                           because it's static */ } 
}

Die Regel zum Speichern ist einfach: Eine Methode in einer erweiterten Klasse kann statisch nicht in void und void nicht in statisch ändern. Dies führt zu Kompilierungsfehlern.

Aber wenn void Namegeändert wird, ist void Namees Overriding.

Und wenn static Namegeändert wird, ist static Namees Verstecken. (Je nach Art der Referenz, die zum Aufrufen der Methode verwendet wird, können sowohl die statische Methode der Unterklasse als auch die der Oberklasse aufgerufen werden.)

p.karnaukhov
quelle
1

In diesem Codeausschnitt verwende ich den Zugriffsmodifikator "privat" anstelle von "statisch", um Ihnen den Unterschied zwischen ausgeblendeten und überschreibenden Methoden zu zeigen.

class Animal {
// Use 'static' or 'private' access modifiers to see how method hiding work.
private void testInstancePrivateMethod(String source) {
    System.out.println("\tAnimal: instance Private method calling from "+source);
}
public void testInstanceMethodUsingPrivateMethodInside() {
    System.out.println("\tAnimal: instance Public method with using of Private method.");
    testInstancePrivateMethod( Animal.class.getSimpleName() );
}

// Use default, 'protected' or 'public' access modifiers to see  how method overriding work.
protected void testInstanceProtectedMethod(String source) {
    System.out.println("\tAnimal: instance Protected method calling from "+source);
}
public void testInstanceMethodUsingProtectedMethodInside() {
    System.out.println("\tAnimal: instance Public method with using of Protected method.");
    testInstanceProtectedMethod( Animal.class.getSimpleName() );
  } 
}  


public class Cat extends Animal {
private void testInstancePrivateMethod(String source) {
    System.out.println("Cat: instance Private method calling from " + source );
}
public void testInstanceMethodUsingPrivateMethodInside() {
    System.out.println("Cat: instance Public method with using of Private method.");
    testInstancePrivateMethod( Cat.class.getSimpleName());
    System.out.println("Cat: and calling parent after:");
    super.testInstanceMethodUsingPrivateMethodInside();
}

protected void testInstanceProtectedMethod(String source) {
    System.out.println("Cat: instance Protected method calling from "+ source );
}
public void testInstanceMethodUsingProtectedMethodInside() {
    System.out.println("Cat: instance Public method with using of Protected method.");
    testInstanceProtectedMethod(Cat.class.getSimpleName());
    System.out.println("Cat: and calling parent after:");
    super.testInstanceMethodUsingProtectedMethodInside();
}

public static void main(String[] args) {
    Cat myCat = new Cat();
    System.out.println("----- Method hiding -------");
    myCat.testInstanceMethodUsingPrivateMethodInside();
    System.out.println("\n----- Method overriding -------");
    myCat.testInstanceMethodUsingProtectedMethodInside();
}
}

Ausgabe:

----- Method hiding -------
Cat: instance Public method with using of Private method.
Cat: instance Private method calling from Cat
Cat: and calling parent after:
   Animal: instance Public method with using of Private method.
   Animal: instance Private method calling from Animal

----- Method overriding -------
Cat: instance Public method with using of Protected method.
Cat: instance Protected method calling from Cat
Cat: and calling parent after:
   Animal: instance Public method with using of Protected method.
Cat: instance Protected method calling from Animal
Rustem Zhunusov
quelle
Ich frage mich, warum es nicht die positiven Stimmen bekommen hat. Sehr geschätzte Antwort.
Amarnath Harish
0

Basierend auf meinen letzten Java-Studien

  • Überschreiben der Methode , wenn die Unterklasse dieselbe Methode mit derselben Signatur in der Unterklasse hat.
  • Ausblenden der Methode , wenn die Unterklasse denselben Methodennamen, aber unterschiedliche Parameter hat. In diesem Fall überschreiben Sie die übergeordnete Methode nicht, sondern verbergen sie.

Beispiel aus dem OCP Java 7-Buch, Seite 70-71:

public class Point {
  private int xPos, yPos;
  public Point(int x, int y) {
        xPos = x;
        yPos = y;
  }

  public boolean equals(Point other){
  .... sexy code here ...... 
  }

  public static void main(String []args) {
   Point p1 = new Point(10, 20);
   Point p2 = new Point(50, 100);
   Point p3 = new Point(10, 20);
   System.out.println("p1 equals p2 is " + p1.equals(p2));
   System.out.println("p1 equals p3 is " + p1.equals(p3));
   //point's class equals method get invoked
  }
}

aber wenn wir folgendes schreiben:

  public static void main(String []args) {
   Object p1 = new Point(10, 20);
   Object p2 = new Point(50, 100);
   Object p3 = new Point(10, 20);
   System.out.println("p1 equals p2 is " + p1.equals(p2));
   System.out.println("p1 equals p3 is " + p1.equals(p3));
   //Object's class equals method get invoked
  }

Im zweiten Hauptteil verwenden wir die Object-Klasse als statischen Typ. Wenn wir also die Equal-Methode im Point-Objekt aufrufen, wartet eine Point-Klasse darauf, als Parameter anzukommen, aber das Objekt kommt. Die Object-Klasse entspricht also der Methode, die ausgeführt wird, da wir dort ein Equals (Object o) haben. In diesem Fall überschreibt die Klasse des Punkts gleich nicht, sondern verbirgt die Methode Objektklasse gleich .

Karoly
quelle
0
public class Parent {

  public static void show(){
    System.out.println("Parent");
  }
}

public class Child extends Parent{

  public static void show(){
    System.out.println("Child");
  }
}

public class Main {

public static void main(String[] args) {
    Parent parent=new Child();
    parent.show(); // it will call parent show method
  }
}

// We can call static method by reference ( as shown above) or by using class name (Parent.show())
Deepak
quelle
0

Die verknüpfte Java-Tutorial-Seite erklärt das Konzept des Überschreibens und Versteckens

Eine Instanzmethode in einer Unterklasse mit derselben Signatur (Name plus Nummer und Typ ihrer Parameter) und Rückgabetyp als Instanzmethode in der Oberklasse überschreibt die Methode der Oberklasse.

Wenn eine Unterklasse eine statische Methode mit derselben Signatur wie eine statische Methode in der Oberklasse definiert, verbirgt die Methode in der Unterklasse die in der Oberklasse.

Die Unterscheidung zwischen dem Ausblenden einer statischen Methode und dem Überschreiben einer Instanzmethode hat wichtige Auswirkungen:

  1. Die Version der überschriebenen Instanzmethode, die aufgerufen wird, ist die in der Unterklasse.
  2. Die Version der versteckten statischen Methode, die aufgerufen wird, hängt davon ab, ob sie von der Oberklasse oder der Unterklasse aufgerufen wird.

Zurück zu Ihrem Beispiel:

Animal myAnimal = myCat;

 /* invokes static method on Animal, expected. */
 Animal.testClassMethod(); 

 /* invokes child class instance method (non-static - it's overriding) */
 myAnimal.testInstanceMethod();

Die obige Aussage zeigt noch kein Verstecken.

Ändern Sie nun den Code wie folgt, um eine andere Ausgabe zu erhalten:

  Animal myAnimal = myCat;
  
  /* Even though myAnimal is Cat, Animal class method is invoked instead of Cat method*/
  myAnimal.testClassMethod();
  
  /* invokes child class instance method (non-static - it's overriding) */
  myAnimal.testInstanceMethod();
Ravindra Babu
quelle
Ich versuche zu verstehen, was das Wort "sich verstecken" bedeutet. Was versteckt was? Ist die statische Methode in der Parent-Klasse ausgeblendet, weil sie (am wenigsten erwartet) aufgerufen wird? Oder ist die statische Methode in der Child-Klasse ausgeblendet, weil sie nicht aufgerufen wird?
Skorpion
0

Zusätzlich zu den oben aufgeführten Beispielen finden Sie hier einen kleinen Beispielcode, um die Unterscheidung zwischen Ausblenden und Überschreiben zu verdeutlichen:

public class Parent {

    // to be hidden (static)
    public static String toBeHidden() {
        return "Parent";
    }

    // to be overridden (non-static)
    public String toBeOverridden() {
        return "Parent";
    }

    public void printParent() {
        System.out.println("to be hidden: " + toBeHidden());
        System.out.println("to be overridden: " + toBeOverridden());
    }
}

public class Child extends Parent {

    public static String toBeHidden() {
        return "Child";
    }

    public String toBeOverridden() {
        return "Child";
    }

    public void printChild() {
        System.out.println("to be hidden: " + toBeHidden());
        System.out.println("to be overridden: " + toBeOverridden());
    }
}

public class Main {

    public static void main(String[] args) {
        Child child = new Child();
        child.printParent();
        child.printChild();
    }
}

Der Aufruf von child.printParent()Ausgaben:
versteckt werden: Eltern
überschrieben werden: Kind

Der Aufruf der child.printChild()Ausgaben:
versteckt werden: Kind
überschrieben werden: Kind

Wie aus den obigen Ausgaben (insbesondere den fett markierten Ausgaben) hervorgeht, verhält sich das Ausblenden von Methoden anders als das Überschreiben.

Java erlaubt das Ausblenden und Überschreiben nur für Methoden. Die gleiche Regel gilt nicht für Variablen. Das Überschreiben von Variablen ist nicht zulässig, daher können Variablen nur ausgeblendet werden (kein Unterschied zwischen statischen und nicht statischen Variablen). Das folgende Beispiel zeigt, wie die Methode getName()überschrieben und die Variable nameausgeblendet wird:

public class Main {

    public static void main(String[] args) {
        Parent p = new Child();
        System.out.println(p.name); // prints Parent (since hiding)
        System.out.println(p.getName()); // prints Child (since overriding)
    }
}

class Parent {
    String name = "Parent";

    String getName() {
        return name;
    }
}

class Child extends Parent {
    String name = "Child";

    String getName() {
        return name;
    }
}
Nurettin Armutcu
quelle
0

Zur Laufzeit wird die untergeordnete Version einer überschriebenen Methode immer für eine Instanz ausgeführt, unabhängig davon, ob der Methodenaufruf in einer übergeordneten oder untergeordneten Klassenmethode definiert ist. Auf diese Weise wird die übergeordnete Methode nur verwendet, wenn auf einen expliziten Aufruf der übergeordneten Methode unter Verwendung der Syntax ParentClassName.method () verwiesen wird. Alternativ wird zur Laufzeit die übergeordnete Version einer versteckten Methode immer ausgeführt, wenn der Aufruf der Methode in der übergeordneten Klasse definiert ist.

Carrieukie
quelle
0

Beim Überschreiben von Methoden erfolgt die Methodenauflösung durch die JVM auf der Grundlage des Laufzeitobjekts. Während beim Ausblenden von Methoden die Methodenauflösung vom Compiler auf der Grundlage von Referenzen vorgenommen wird. So,

Wenn der Code geschrieben worden wäre als,

public static void main(String[] args) {
        Animal myCat = new Cat();        
        myCat.testClassMethod();        
    }

Die Ausgabe wäre wie folgt:
Klassenmethode in Tier.

SagarS
quelle
0

Es wird als Ausblenden bezeichnet, da der Compiler die Implementierung der Superklassenmethode verbirgt, wenn die Unterklasse dieselbe statische Methode hat.

Der Compiler hat keine eingeschränkte Sichtbarkeit für überschriebene Methoden und nur zur Laufzeit wird entschieden, welche verwendet wird.

Gadam
quelle
0

Dies ist der Unterschied zwischen Überschreiben und Verstecken:

Tier a = neue Katze ();

a.testClassMethod () ruft die Methode in der übergeordneten Klasse auf, da dies ein Beispiel für das Ausblenden von Methoden ist. Die aufzurufende Methode wird durch den Typ der Referenzvariablen bestimmt und zur Kompilierungszeit festgelegt.

a.testInstanceMethod () ruft die Methode in der untergeordneten Klasse auf, da dies ein Beispiel für das Überschreiben von Methoden ist. Die aufzurufende Methode wird durch das Objekt bestimmt, mit dem die Methode zur Laufzeit aufgerufen wird.

Kinshuk
quelle
-1

Wie geschieht das Verstecken statischer Methoden in Java? Die Katzenklasse erweitert die Tierklasse. In der Cat-Klasse gibt es also beide statischen Methoden (ich meine die statische Methode der Child-Klasse und die statische Methode der Parent-Klasse). Aber wie versteckt JVM die statische Parent-Methode? Wie geht es mit Heap and Stack?

user3924979
quelle
Dies ist keine Antwort. Es ist die Erweiterung der gestellten Frage. Möglicherweise handelt es sich um eine separate Frage selbst oder um einen Teil der Kommentare zu dieser Frage.
Sri9911