2015-08-24 5 views
32

Ich bin immer noch ziemlich frisch, aber ich arbeite daran, meine OCAJP-Zertifizierung (Java) zu erreichen. Ich erinnerte mich vorher zu lesen, dass die .equals Methode außer Kraft gesetzt werden könnte, wenn ich auf diese Frage kam:10 Können .equals überschrieben werden, sodass a.equals (a) false zurückgibt?

Question from Enthuware prep materials:

Nun sind diese Fragen ziemlich böse gewesen sind, so weit es mich betrifft. Verdrehen jedes kleine Ding, von dem Sie denken, dass Sie es wissen, um Sie zu zwingen, alle Details zu lernen. Jetzt hatte ich E erraten, aber ich dachte nicht, dass D richtig war. Ich meine natürlich 99,9% der Zeit, aber ich dachte, es wäre eine Trickfrage, die auf dem Wortlaut basiert.

Das hat mich denken lassen, ist das wahr? Ich meine, wenn ich die Frage über die Prüfung bekomme, weiß ich, wie ich sie jetzt beantworten soll, aber in dem tiefen dunklen Abgrund des übergeordneten Wahnsinns ist es möglich, eine Situation zu schaffen, in der a.equals (a) falsch zurückgibt? Ich glaube, das würde Aristoteles wütend machen ...

+1

Ich denke nicht, dass das überhaupt ein böser_ ist - es fragt nur, was man von Basisklassen der Sprache erwarten kann. Es wäre _evil_, zu fragen, ob eine benutzerdefinierte Klasse 'equals' überschreiben könnte, so dass' a.equals (a) '' 'false' 'ist, wie man das technisch tun kann, aber _shouldn't_, da man den' equals' Kontakt verletzen würde . – mgarciaisaia

+0

Ich meine, fange nicht an zu denken - diese Frage ist _evil_, weil du mit dieser Einstellung zu voreingenommen bist, um richtig darüber nachzudenken, was du während der Prüfung weißt. – mgarciaisaia

+0

Ich glaube, das Problem ist, dass es nicht angegeben, dass sie * die * primitiven Wrapper-Klassen im Gegensatz zu jeder zufälligen primitiven Wrapper-Klasse waren. –

Antwort

47

Beachten Sie, dass a. b und c sind Instanzen primitiver Wrapper-Klassen (wie Integer, Double, etc ...). Diese Klassen sind endgültig und können nicht erweitert werden, sodass Sie ihre equals Implementierung nicht überschreiben können.

Daher gibt a.equals(a) immer True zurück, da diese Klassen equals richtig implementieren.

+0

Okay, also war das Schwierige an dieser Frage der Wrapperklassenanteil, den ich vermisst habe. Vielen Dank! Aber wenn es darum geht, die Welt mit .equals auf den Kopf zu stellen, ist das in nicht-finalen Klassen noch möglich? –

+0

Sie beziehen sich wahrscheinlich auf andere Klassen, nicht auf die Wrapper von Primitiven. In diesem Fall können Sie equals beliebig überschreiben. –

+9

@StevetheMaker Sie können immer eine nicht-finale Klasse erweitern und Gleichheiten mit 'public boolean equals (Object other) {return false;}' überschreiben. Das macht keinen Sinn, aber Sie können es tun. – Eran

1

Sie können sich die Implementierungen aller primitiven Wrapper ansehen, d. H. Integer, Boolean, Character etc ... Sie werden sehen, dass die Implementierung korrekt ist.
Der Grund dafür ist, dass bei equals nach der Prüfung die Referenzgleichheit überprüft wird und x.equals (x) als Objekt und Argument dasselbe Objekt ist.

21

Da equals(...) ist keine endgültige Methode von Object, ja, es ist sehr gut möglich in einer anderen Situation.

@Override 
public boolean equals(Object obj) { 
    return false; 
} 

Diese Frage ist jedoch, sagt ausdrücklich, dass diese primitive Wrapper sind (z Integer, Boolean, etc.) und da diese Klassen endgültig sind, können Sie sie nicht verlängern kann, wird somit a.equals(a) immer true zurück.

6

Die anderen Antworten haben Ihre Frage bereits beantwortet - nein, das ist mit den primitiven Wrapper-Klassen von Java nicht möglich.

Ich werde versuchen, die "Frage hinter der Frage" zu beantworten: Ist das mit anderen Klassen möglich?

[...] in den tiefen dunklen Abgrund Wahnsinn überschreiben, ist es möglich, eine Situation zu schaffen, in der a.equals (a) false zurückgibt? Ich fühle mich wie dieser würde Aristoteles wütend machen ...

Dies ist eigentlich eine gute Frage, und die Antwort lautet: Ja, es ist möglich, eine solche Situation zu schaffen, und ja, es würde Aristoteles wütend. Eigentlich weiß ich nicht, ob es Aristoteles ärgern würde, dass er ihn nicht gekannt hat, aber es wird sicherlich viel Kummer für diejenigen verursachen, die mit dem Code arbeiten müssen.

Die Sache ist die: Es gibt einen Vertrag im Zusammenhang mit Object.equals():

Die Gleichheits Verfahren implementiert eine Äquivalenzrelation auf nicht-null Objektreferenzen:

[...]

Es ist reflexiv: Für alle Nicht-Null-Referenzwert x, x.equals (x) sollte True zurückgeben.

Javadocs for Object.equals

Ja, wenn Sie Ihre eigene Klasse erstellen, können Sie diesen Vertrag verletzen. Es gibt (leider) nichts im Compiler oder in der Runtime, das Sie stoppt.

Allerdings hängt viel Code von diesem Vertrag ab. Wenn Sie ihn also verletzen, wird jeder Code, der equals verwendet, wahrscheinlich auf mysteriöse Weise fehlschlagen. Ein Beispiel: Javas eigene Collection-Klassen (java.util.Collection und Freunde) basieren auf equals. Wenn eine Instanz einer Klasse, die equals nicht korrekt implementiert, in eine Sammlung eingefügt wird, passieren seltsame Dinge, wie zum Beispiel die Sammlung, die manchmal die Instanz enthält und manchmal nicht.

+1

Eine Beziehung kann symmetrisch und antireflexiv sein. (Natürlich gibt das Javadoc, auf das Sie verlinken, auch die Reflexivität an) – Taemyr

+1

@Taemyr: Ja, eine _relation_ kann antireflexiv sein, aber eine _äquivalenzrelation_ ist per Definition reflexiv. Kleiner aber wichtiger Unterschied :-). – sleske

+0

Sicher, das lässt immer noch die Frage offen, warum die eine Eigenschaft, die Sie auswählen, die Symmetrie ist. - In Anbetracht dessen, dass die Frage ausdrücklich die Reflexivität betrifft. – Taemyr

7

Integer a.equals (a) falsch

zurückkehren Aber Sie haben wirklich böse sein und Reflexionen und Multithreading verwenden:

Wenn Sie diesen Code ausführen, gibt es eine Chance, dass eine Bedingung Rennen kann Ändern Sie den internen Wert von myInt, während der Vergleich stattfindet. Wenn Sie diese Bedingung simulieren möchten, setzen Sie einfach einen Haltepunkt innerhalb von Integer.intValue(), führen Sie den Code in debug aus und klicken Sie auf Weiter. Dies erzeugt eine Verzögerung, die künstlich die Race-Bedingung erzeugt und die Konsole wird false zurückgeben.

class IntegerEqualsTest 
{ 
    public static void main(final String[] args) 
    { 
     final Integer myInt = new Integer(420); 

     new Thread() { 
      public void run() { 
       try { 
        final Field f = Integer.class.getDeclaredField("value"); 
        f.setAccessible(true); 
        f.setInt(myInt, 100); 
       } catch(final Exception e) {} 
      }; }.start(); 

     System.out.println(myInt.equals(myInt)); 
    } 
} 
+3

Während dieses Stück Code clever und böse ist, nutzt es keine übergreifenden Methoden (Formulierung der ursprünglichen Frage) oder einen speziellen Mechanismus für "equals". Das Schreiben von Thread-Sicherheitscode kann eine Vielzahl von Problemen auslösen, nicht nur das, sondern auch das Halten eines Uran-235-Sticks in der Nähe des RAM im Computer. :) – nitro2k01

+0

@ nitro2k01 Ich würde diesen Thread nicht einmal unsicher nennen, da das Setzen eines ganzzahligen Wertes normalerweise eine atomare Operation ist, also ist dieser Code nur semantisch Thread unsicher, nicht auf einer niedrigen Sprachlevel. – Falco

+1

Nun, technisch thread sicher oder nicht, die Idee, dass Sie gehen und einen Wert aus einem anderen Thread ändern können, bringt Unsicherheit auf _exactly_ _every_ Frage, und tut nichts, um das Verhalten der equals-Methode an sich zu charakterisieren. – nitro2k01