Frage

Gestern hatte ich ein zweistündiges technisches Telefoninterview (das ich bestanden habe, woohoo!), aber ich habe die folgende Frage zur dynamischen Bindung in Java völlig vermasselt.Und es ist doppelt rätselhaft, weil ich dieses Konzept vor ein paar Jahren als TA den Studenten beigebracht habe, daher ist die Aussicht, dass ich ihnen Fehlinformationen gegeben habe, ein wenig beunruhigend ...

Hier ist das Problem, das mir gestellt wurde:

/* What is the output of the following program? */

public class Test {

  public boolean equals( Test other ) {
    System.out.println( "Inside of Test.equals" );
    return false;
  }

  public static void main( String [] args ) {
    Object t1 = new Test();
    Object t2 = new Test();
    Test t3 = new Test();
    Object o1 = new Object();

    int count = 0;
    System.out.println( count++ );// prints 0
    t1.equals( t2 ) ;
    System.out.println( count++ );// prints 1
    t1.equals( t3 );
    System.out.println( count++ );// prints 2
    t3.equals( o1 );
    System.out.println( count++ );// prints 3
    t3.equals(t3);
    System.out.println( count++ );// prints 4
    t3.equals(t2);
  }
}

Ich habe behauptet, dass die Ausgabe zwei separate Druckanweisungen innerhalb der überschriebenen sein sollte equals() Methode:bei t1.equals(t3) Und t3.equals(t3).Der letztere Fall liegt auf der Hand, und der erste Fall gilt auch dafür t1 Hat eine Referenz vom Typ Object, wird sie als Typ Test instanziiert, daher sollte die dynamische Bindung die überschriebene Form der Methode aufrufen.

Scheinbar nicht.Mein Interviewer ermutigte mich, das Programm selbst auszuführen, und siehe da, es gab nur eine einzige Ausgabe der überschriebenen Methode:an der Linie t3.equals(t3).

Meine Frage ist dann, warum?Wie ich bereits erwähnt habe, obwohl t1 ist eine Referenz vom Typ Object (die statische Bindung würde also Objects aufrufen equals() Methode), dynamische Bindung sollen Achten Sie darauf, die spezifischste Version der Methode basierend auf dem instanziierten Typ der Referenz aufzurufen.Was vermisse ich?

War es hilfreich?

Lösung

Java verwendet statische für überladene Methoden Bindung und dynamische für überschriebene diejenigen verbindlich. In Ihrem Beispiel wird die Methode equals überlastet (hat einen anderen param Typen als Object.equals ()), so genannt, das Verfahren auf die Referenz gebunden Typ bei der Kompilierung.

Einige Diskussion hier

Die Tatsache, dass es das Gleichheits ist Methode nicht wirklich relevant ist, anders als es ein häufiger Fehler ist es, um eine Überlastung statt überschreibt, die Sie bereits von in dem Interview für das Problem auf Ihre Antwort bewusst sind.

Edit: Eine gute Beschreibung hier auch. Dieses Beispiel ist ein ähnliches Problem mit dem Parameter mit dem gleichen Problem geben stattdessen aber verursacht im Zusammenhang zeigt.

Ich glaube, wenn die Bindung tatsächlich dynamisch war, dann jeder Fall, in dem der Anrufer und der Parameter eine Instanz von Tests wurden in der überschriebenen Methode aufgerufen wird, führen würde. So t3.equals (o1) wäre der einzige Fall sein, die nicht gedruckt werden würde.

Andere Tipps

Die equals Methode des Test überschreibt nicht die equals Methode des java.lang.Object. Schauen Sie sich die Parameter-Typ! Die Test Klasse Überlastung equals mit einer Methode, die eine Test akzeptiert.

Wenn die equals Methode soll außer Kraft zu setzen, sollte es die @Override Anmerkung verwenden. Dies würde einen Kompilierungsfehler verursacht diese häufigen Fehler hinweisen.

Interessanterweise in Groovy-Code (die zu einer Klasse-Datei kompiliert werden könnte), alle bis auf einen der Anrufe über die print-Anweisung würde ausführen. (Die man einen Test, um ein Objekt zu vergleichen eindeutig nicht die Test.equals (Test) Funktion aufrufen.) Dies liegt daran, groovy vollständig dynamische Typisierung tut. Dies ist insbesondere dann von Interesse, weil es keine Variablen, die explizit dynamisch typisiert werden. Ich habe in ein paar Stellen gelesen, dass diese schädlich angesehen werden, als Programmierer groovy erwartet, dass die Java-Sache zu tun.

Java nicht Kovarianz in Parametern unterstützt, nur in Rückgabetypen.

Mit anderen Worten, während des Rückgabetyp in einem übergeordneten Verfahren ein Subtyp von sein kann, was es in den überschriebenen war, dh für die Parameter nicht wahr.

Wenn Ihr Parameter für equals in Object ist, setzt ein Gleichheits mit irgendetwas anderes in einer Unterklasse wird eine überlastet werden, nicht eine überschriebene Methode. Daher, wo die einzige Situation, diese Methode aufgerufen wird, ist, wenn der statische Typ des Parameters-Test ist, wie im Fall von T3.

Viel Glück mit dem Vorstellungsgespräch Prozess! Ich würde gerne in einem Unternehmen befragt werden, die diese Art von Fragen statt der üblichen algo / Datenstrukturen Fragen stellt, die ich meine Schüler beibringen.

Ich denke, der Schlüssel liegt in der Tatsache, dass die Methode equals () nicht zur Standard nicht entspricht: Es dauert in einem anderen Test-Objekt, nicht Objekt Objekt und somit zwingenden nicht die equals () -Methode. Das heißt, Sie haben es eigentlich nur überlastet, etwas Besonderes zu tun, wenn es Prüfgegenstand gegeben hat, während es Aufgabe geben Objekt aufruft Object.equals (Object o). dass Code durch jede IDE suchen, sollten Sie zwei equals () Methoden für Test zeigen.

Das Verfahren wird anstelle von überschriebenen überlastet. Equals immer ein Objekt als Parameter übernehmen.

btw, haben Sie einen Artikel zu diesem Thema in Blochs Effective Java (das sollten Sie besitzen).

Einige Notiz in Dynamische Bindung (DD) und statische Bindung (SB) nach Suche eine Weile:

1.Timing ausführen : (Sollw1)

  • DB: zur Laufzeit
  • SB: Compiler Zeit

2.Used für :

  • DB: Überschreiben
  • SB: Überlastung (statisch, privat, final) (Sollw2)

Hinweis:

  1. Ausführen mittlere Resolver, welche Methode zu verwenden, bevorzugen
  2. Da kann nicht zwingende Methode mit Modifikator statisch, private oder final
  3. http: // javarevisited. blogspot.com/2012/03/what-is-static-and-dynamic-binding-in.html

Wenn eine weitere Methode hinzugefügt wird, die überschreibt statt überlädt, erklärt dies den dynamischen Bindungsaufruf zur Laufzeit.

/* Was ist die Ausgabe des folgenden Programms?*/

public class DynamicBinding {
    public boolean equals(Test other) {
        System.out.println("Inside of Test.equals");
        return false;
    }

    @Override
    public boolean equals(Object other) {
        System.out.println("Inside @override: this is dynamic binding");
        return false;
    }

    public static void main(String[] args) {
        Object t1 = new Test();
        Object t2 = new Test();
        Test t3 = new Test();
        Object o1 = new Object();

        int count = 0;
        System.out.println(count++);// prints 0
        t1.equals(t2);
        System.out.println(count++);// prints 1
        t1.equals(t3);
        System.out.println(count++);// prints 2
        t3.equals(o1);
        System.out.println(count++);// prints 3
        t3.equals(t3);
        System.out.println(count++);// prints 4
        t3.equals(t2);
    }
}

Ich fand einen interessanten Artikel über dynamische und statische Bindung. Es kommt mit einem Stück Code für die dynamische Bindung zu simulieren. Es machte meinen Code ein lesbarer.

https://sites.google.com/site/jeffhartkopf/covariance

Siehe auch diese Frage SO, eng verwandt: Aufschalten der JAVA Methode equals Marotte

Die Antwort auf die Frage „Warum?“ ist das ist, wie die Java-Sprache definiert ist.

die Wikipedia-Artikel über Kovarianz und Kontra zu zitieren:

  

Rückgabetyp Kovarianz implementiert   in der Programmiersprache Java   Version J2SE 5.0. Parametertypen haben   genau das gleiche (invariant) zu sein,   Methode überschreiben, da sonst die   Verfahren wird mit einem parallel überlastet   Definition statt.

Weitere Sprachen sind unterschiedlich.

Es ist sehr klar, dass es kein Konzept ist hier zu überschreiben. Es ist Methode Überlastung. die Object() Methode der Objektklasse Parameter Referenz vom Typ Object nimmt und diese equal() Methode nimmt Parameter der Referenz des Typs Prüfung.

Ich werde versuchen, dies durch zwei Beispiele zu erklären, die die erweiterten Versionen von einigen der Beispiele, die ich über Online kam.

public class Test {

    public boolean equals(Test other) {
        System.out.println("Inside of Test.equals");
        return false;
    }

    @Override
    public boolean equals(Object other) {
        System.out.println("Inside of Test.equals ot type Object");
        return false;
    }

    public static void main(String[] args) {
        Object t1 = new Test();
        Object t2 = new Test();
        Test t3 = new Test();
        Object o1 = new Object();

        int count = 0;
        System.out.println(count++); // prints 0
        o1.equals(t2);

        System.out.println("\n" + count++); // prints 1
        o1.equals(t3);

        System.out.println("\n" + count++);// prints 2
        t1.equals(t2);

        System.out.println("\n" + count++);// prints 3
        t1.equals(t3);

        System.out.println("\n" + count++);// prints 4
        t3.equals(o1);

        System.out.println("\n" + count++);// prints 5
        t3.equals(t3);

        System.out.println("\n" + count++);// prints 6
        t3.equals(t2);
    }
}

Hier für Linien mit Zählwerte 0, 1, 2 und 3; wir haben Hinweis Objekt für o1 und t1 auf der equals() Methode. Somit wird bei der Kompilierung, die equals() Methode aus den Object.class Datei begrenzt werden.

Doch obwohl Hinweis von t1 ist Object , hat es intialization Testklasse .
Object t1 = new Test();.
Daher zur Laufzeit ruft er die public boolean equals(Object other), die ein

ist
  

außer Kraft gesetzt Methode

. eingeben Bild Beschreibung hier

Nun, für Zählwerte als 4 und 6 ist es wieder einfach, dass t3 , das hat Hinweis und Initialisierung von Prüfungs ruft equals() Methode mit dem Parameter als Objektreferenzen und ist ein

  

überladene Methode

OK!

  

Auch hier besser zu verstehen, welche Methode der Compiler nennen, nur   klicken Sie auf das Verfahren und Eclipse werden die Methoden ähnlicher markieren   Typen, die es bei der Kompilierung denkt nennen. Wenn es nicht bekommen   zum Zeitpunkt der Kompilierung aufgerufen, dann sind diese Methoden ein Beispiel eines Verfahrens   overridding.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top