Ich übe für eine Prüfung und habe ein Beispielproblem gefunden, das ich nicht verstehe.
Suchen Sie für den folgenden Code nach der Ausgabe:
public class Test {
private static int count = 0;
public boolean equals(Test testje) {
System.out.println("count = " + count);
return false;
}
public static void main(String [] args) {
Object t1 = new Test();
Object t2 = new Test();
Test t3 = new Test();
Object o1 = new Object();
++count; t1.equals(t2);
++count; t1.equals(t3);
++count; t3.equals(o1);
++count; t3.equals(t3);
++count; t3.equals(t2);
}
}
Die Ausgabe dieses Codes ist count = 4
, aber ich verstehe nicht warum. Kann mir jemand helfen?
Antworten:
Das erste , was man beachten sollte , ist , dass
public boolean equals(Test testje)
nicht nicht außer Kraft gesetztObject
istequals
, da das ArgumentTest
stattObject
, so dass die Signaturen nicht übereinstimmen.Daher
main
ruft die Methodeequals(Test testje)
bei der Ausführung genau einmal auf,t3.equals(t3);
da dies der einzige Fall ist, in dem sowohl der statische Typ der Instanzequals
als auch der Typ des Arguments dieTest
Klasse sind.t3.equals(t3);
ist die 4.equals
Anweisung (die nach 4 Inkrementen der statischencount
Variablen kommt), also werden 4 gedruckt.Alle anderen
equals
Anweisungen ausgeführtObject
istequals
und daher nichts drucken.Eine detailliertere Erklärung:
t1.equals()
AnrufeObject
sindequals
unabhängig von der Art des Arguments, da der statischen (Kompilierung) Typt1
istObject
, und dieTest
Klasse überschreibt nicht diese Methode. DieObject
Klasse hat keineequals
Methode mit einem einzelnenTest
Argument undequals(Test testje)
kann daher unabhängig von der Dynamik (Laufzeitart) von nicht aufgerufen werdent1
.t3.equals()
kann entwederObject
'sequals
oderTest
' s gleich ausführen , da der Kompilierungszeittyp vont3
istTest
und dieTest
Klasse zweiequals
Methoden hat (eine von derObject
Klasse geerbt und die andere in derTest
Klasse definiert ).Die gewählte Methode hängt vom Kompilierungszeittyp des Arguments ab: 1. Wenn das Argument
Object
(wie int3.equals(o1);
odert3.equals(t2);
) lautet , wirdObject
'sequals
aufgerufen und nichts gedruckt. 2. Wenn das ArgumentTest
wie in istt3.equals(t3);
,equals
stimmen beide Versionen mit diesem Argument überein, aber aufgrund der Regeln der Methodenüberladung wird die Methode mit dem spezifischsten Argument -equals(Test testje)
- ausgewählt und diecount
Variable gedruckt.quelle
Die Methode equals in Test verwendet eine Testinstanz.
Alle vorherigen Versuche wurden mit einer Instanz von Object durchgeführt, die die geerbte Methode aus der Object-Klasse übernimmt:
public boolean equals(Object o){ return this == o; }
Da dort kein Druck vorhanden ist, wird kein Wert gedruckt.
Sie
++count;
erhöhen den Wert von count, also den Moment, in dem Sie Ihren tatsächlich anrufenpublic boolean equals(Test testje){...
Methode, die diesen Wert druckt, ist der Wert von count 4.
quelle
t3.equals(t3)
ist die einzige Zeile mit den richtigen Argumenten, die mit der Methodensignatur übereinstimmen.public boolean equals (Test testje)
Es ist also die einzige Zeile im Programm, die diese print-Anweisung tatsächlich aufruft. Diese Frage soll Ihnen einige Dinge beibringen.Der Trick dabei ist im Wesentlichen, dass Test Object implizit erweitert, wie es alle Java-Klassen tun. Object enthält eine equals-Methode vom Typ Object. t1 und t2 werden so typisiert, dass die Argumente zur Laufzeit niemals mit der in Test definierten Methodensignatur von equals übereinstimmen. Stattdessen wird immer die Methode equals in Object.java aufgerufen, da entweder der Basistyp Is Object ist. In diesem Fall haben Sie nur Zugriff auf die in Object.java definierten Methoden, oder der abgeleitete Typ ist Object. In diesem Fall
public boolean equals(Test testje)
Kann nicht eingegeben werden, da in diesem Fall das Argument zur Laufzeit vom Typ Object ist, bei dem es sich um eine Superklasse des Tests und nicht um eine Unterklasse handelt. Stattdessen wird die Methode equals in der implizit typisierten Superklasse Object.java von Test.java betrachtet, die auch eine Methode equals enthält, die zufällig eine Methodensignatur von hat
public boolean equals (Object o)
die in diesem Fall mit unseren Argumenten zur Laufzeit übereinstimmen, sodass diese Methode gleich ist, die ausgeführt wird.
Beachten Sie, dass
t3.equals(t3)
sowohl der Basistyp als auch der abgeleitete Typ von t3 Test sind.Test t3 = new Test ();
Dies bedeutet, dass Sie zur Laufzeit die Methode equals in Test.java aufrufen und das Argument, das Sie übergeben, tatsächlich vom Typ Test ist, sodass die Methodensignaturen übereinstimmen und der Code in Test.java ausgeführt wird. An diesem Punkt
count == 4
.Bonuswissen für Sie:
@Override
Anmerkungen, die Sie möglicherweise an einigen Stellen gesehen haben, weisen den Compiler explizit an, fehlzuschlagen, wenn er irgendwo in einer Superklasse keine Methode mit genau derselben Signatur findet. Dies ist hilfreich, um zu wissen, ob Sie definitiv beabsichtigen , eine Methode zu überschreiben, und ob Sie absolut sicher sein möchten, dass Sie die Methode wirklich überschreiben und die Methode weder in der Oberklasse noch in der Unterklasse versehentlich geändert haben, jedoch nicht in beiden, und einen Laufzeitfehler eingeführt haben wobei die falsche Implementierung der Methode aufgerufen wird und unerwünschtes Verhalten verursacht.
quelle
Es gibt zwei wichtige Dinge, die Sie wissen sollten.
Überschriebene Methoden müssen genau die Signaturen haben, die ihre Oberklasse hat. (In Ihrem Beispiel erfüllt diese Bedingung nicht.)
In Java für ein Objekt haben wir zwei Typen: Kompilierung Typen und Laufzeittyp . Im folgenden Beispiel ist der Kompilierungstyp von
myobj
is,Object
aber der Laufzeittyp istCar
.public class Car{ @Override public boolean equals(Object o){ System.out.println("something"); return false; } }
Object myobj = new Car();
Beachten Sie auch, dass dies
myobj.equals(...)
zum Druckensomething
in der Konsole führt.quelle
equals
die Oberklasse keine Methode mit derselben Methodensignatur enthält. @Override Annotation soll dem Compiler mitteilen, dass es in einer Oberklasse etwas mit dieser genauen Methodensignatur geben sollte - bitte beschweren Sie sich, wenn dies nicht der