Java: Integer ist gleich vs. ==

152

Ab Java 1.5, können Sie ziemlich viel Austausch Integermit intin vielen Situationen.

Ich habe jedoch einen möglichen Fehler in meinem Code gefunden, der mich ein wenig überrascht hat.

Der folgende Code:

Integer cdiCt = ...;
Integer cdsCt = ...;
...
if (cdiCt != null && cdsCt != null && cdiCt != cdsCt)
    mismatch = true;

schien die Nichtübereinstimmung falsch einzustellen, wenn die Werte gleich waren, obwohl ich nicht feststellen kann, unter welchen Umständen. Ich habe in Eclipse einen Haltepunkt gesetzt Integerund festgestellt, dass beide Werte 137 sind. Ich habe den booleschen Ausdruck überprüft und festgestellt, dass er falsch ist. Als ich darüber trat, wurde die Nichtübereinstimmung auf true gesetzt.

Ändern der Bedingung in:

if (cdiCt != null && cdsCt != null && !cdiCt.equals(cdsCt))

Das Problem wurde behoben.

Kann jemand etwas Licht ins Dunkel bringen, warum dies passiert ist? Bisher habe ich das Verhalten auf meinem lokalen Host nur auf meinem eigenen PC gesehen. In diesem speziellen Fall hat der Code etwa 20 Vergleiche erfolgreich bestanden, ist jedoch bei 2 fehlgeschlagen. Das Problem war durchweg reproduzierbar.

Wenn es sich um ein weit verbreitetes Problem handelt, sollte es in unseren anderen Umgebungen (Entwickler und Test) Fehler verursachen. Bisher hat jedoch niemand das Problem nach Hunderten von Tests gemeldet, bei denen dieses Code-Snippet ausgeführt wurde.

Ist es immer noch nicht legitim, ==zwei IntegerWerte zu vergleichen ?

Zusätzlich zu all den feinen Antworten unten enthält der folgende Stackoverflow-Link einige zusätzliche Informationen. Es hätte tatsächlich meine ursprüngliche Frage beantwortet, aber da ich Autoboxing in meiner Frage nicht erwähnt habe, wurde es in den ausgewählten Vorschlägen nicht angezeigt:

Warum kann der Compiler / die JVM Autobobing nicht einfach "einfach funktionieren" lassen?

Jeremy Goodell
quelle

Antworten:

238

Die JVM speichert ganzzahlige Werte zwischen. == funktioniert nur für Zahlen zwischen -128 und 127 http://www.owasp.org/index.php/Java_gotchas#Immutable_Objects_.2F_Wrapper_Class_Caching

Adam
quelle
1
Danke, das erklärt sicherlich, warum 137 fehlschlägt! Und es beantwortet auch meine Frage, warum es kein weit verbreitetes Problem ist. In 95% der Fälle, auf die ich stoßen werde, würde der Wert unter 127 liegen. Gut, dies jetzt zu fangen, für die 5%, wo es nicht ist.
Jeremy Goodell
1
Interessante Randnotiz: Bis vor ein paar Wochen waren cdiCt und cdsCt beide Ints, also war das in Ordnung, aber ich musste sie zu Ganzzahlen machen, um zu überprüfen, ob die Nullsituation anders gehandhabt wird ...
Jeremy Goodell
3
@Jeremy Ja, es ist ein ziemlich dunkles Problem, aber in der Regel verwenden Sie .equals () für Objekte und == für Grundelemente. Sie können sich beim Testen der Gleichheit nicht auf Autounboxing verlassen.
Adam
1
Lol, dann melde dich bei dir! Es sieht so aus, als hätte Colin sowieso schon mehr als genug Punkte.
Jeremy Goodell
2
Beachten Sie, dass auch neue Ganzzahl (1)! = Neue Ganzzahl (1). new IMMER gibt eine neue Adresse zurück. Autoboxing verwendet eine zwischengespeicherte Version. Andere Methoden, die Ganzzahlen zurückgeben (ohne sie neu zu erstellen), geben wahrscheinlich auch den zwischengespeicherten Wert zurück.
Bill K
77

Sie können zwei nicht Integermit einfachen ==Objekten vergleichen, sodass die Referenzen in den meisten Fällen nicht identisch sind.

Es gibt einen Trick, bei dem Integerzwischen -128 und 127 Referenzen dieselben sind wie bei Autoboxing-Anwendungen, bei Integer.valueOf()denen kleine Ganzzahlen zwischengespeichert werden.

Wenn der Wert p, der eingerahmt wird, wahr, falsch, ein Byte, ein Zeichen im Bereich von \ u0000 bis \ u007f oder eine int oder kurze Zahl zwischen -128 und 127 ist, dann seien r1 und r2 das Ergebnis von zwei beliebigen Boxumwandlungen von p. Es ist immer so, dass r1 == r2.


Ressourcen:

Zum gleichen Thema:

Colin Hebert
quelle
1
Ist die Garantie von der JLS oder nur für die Oracle JVM?
Thorbjørn Ravn Andersen
Der zitierte Teil stammt von der JLS, es handelt sich also um eine Garantie der JLS
Colin Hebert vom
Betreff: Garantie. Ich würde mich immer noch nicht zu sehr darauf verlassen. new Integer(1) == new Integer(1)ist immer noch falsch.
Thilo
@Thilo new ... == new ...ist immer false.
MC Emperor
2
@Thilo True, immer verwenden, equals()wenn Sie mit Objekten arbeiten. Dies sollte eines der ersten Dinge sein, die man beim Erlernen von Java wissen sollte. Übrigens hätte ich vermutet, dass der Konstruktor von Integerprivat war, dh dass Instanzen immer durch die valueOf()Methode erstellt wurden. Aber ich sehe, dass der Konstruktor öffentlich ist.
MC Emperor
5

Das Problem ist, dass Ihre beiden Integer-Objekte genau das sind, Objekte. Sie stimmen nicht überein, da Sie Ihre beiden Objektreferenzen vergleichen, nicht die darin enthaltenen Werte. Offensichtlich .equalswird überschrieben, um einen Wertevergleich im Gegensatz zu einem Objektreferenzvergleich bereitzustellen.

MattC
quelle
Gute Antwort, aber es erklärt nicht, warum es nur für 137 fehlschlägt.
Jeremy Goodell
4

Integerbezieht sich auf die Referenz, dh wenn Sie Referenzen vergleichen, die Sie vergleichen, wenn sie auf dasselbe Objekt verweisen, nicht auf den Wert. Daher das Problem, das Sie sehen. Der Grund, warum es mit einfachen intTypen so gut funktioniert, ist, dass es den in der enthaltenen Wert entpackt Integer.

Darf ich hinzufügen, dass, wenn Sie das tun, was Sie tun, warum die ifAussage zunächst beginnen sollte?

mismatch = ( cdiCt != null && cdsCt != null && !cdiCt.equals( cdsCt ) );
Wheaties
quelle
4

"==" vergleicht immer den Speicherort oder die Objektreferenzen der Werte. Gleich Methode vergleichen immer die Werte. Equals verwendet aber auch indirekt den Operator "==", um die Werte zu vergleichen.

Integer verwendet den Integer-Cache, um die Werte von -128 bis +127 zu speichern. Wenn der Operator == verwendet wird, um nach Werten zwischen -128 und 127 zu suchen, wird true zurückgegeben. für andere als diese Werte wird false zurückgegeben.

Weitere Informationen finden Sie unter dem Link

Vijay
quelle
0

Neben diesen großartigen Antworten habe ich Folgendes gelernt:

Vergleichen Sie Objekte NIEMALS mit ==, es sei denn, Sie möchten sie anhand ihrer Referenzen vergleichen.

ZhaoGang
quelle
0

==Um die korrekte Verwendung zu gewährleisten, können Sie Integervor dem ==Vergleich einfach einen der verglichenen Werte entpacken , z.

if ( firstInteger.intValue() == secondInteger ) {..

Die zweite wird automatisch entpackt (natürlich müssen Sie zuerst nach nulls suchen ).

Mc Bton
quelle