Java: intero è uguale a ==


152

A partire da Java 1.5, puoi praticamente scambiarti Integercon intmolte situazioni.

Tuttavia, ho trovato un potenziale difetto nel mio codice che mi ha sorpreso un po '.

Il seguente codice:

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

sembra che abbia impostato erroneamente la mancata corrispondenza quando i valori erano uguali, anche se non riesco a determinare in quali circostanze. Ho impostato un punto di interruzione in Eclipse e ho visto che i Integervalori erano entrambi 137, e ho ispezionato l'espressione booleana e ha detto che era falso, ma quando l'ho scavalcato, stava impostando la mancata corrispondenza su vero.

Modifica del condizionale in:

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

risolto il problema.

Qualcuno può fare luce sul perché questo è successo? Finora ho visto solo il comportamento sul mio localhost sul mio PC. In questo caso particolare, il codice ha superato con successo circa 20 confronti, ma non è riuscito il 2. Il problema era costantemente riproducibile.

Se si tratta di un problema prevalente, dovrebbe causare errori negli altri nostri ambienti (sviluppo e test), ma finora nessuno ha segnalato il problema dopo centinaia di test che eseguono questo frammento di codice.

Non è ancora legittimo utilizzare ==per confrontare due Integervalori?

Oltre a tutte le risposte dettagliate di seguito, il seguente link stackoverflow contiene alcune informazioni aggiuntive. In realtà avrebbe risposto alla mia domanda originale, ma poiché non ho menzionato l'autoboxing nella mia domanda, non è stato visualizzato nei suggerimenti selezionati:

Perché il compilatore / JVM non può semplicemente fare in modo che l'autoboxing “funzioni”?

Risposte:


238

La JVM sta memorizzando nella cache i valori interi. == funziona solo con numeri compresi tra -128 e 127 http://www.owasp.org/index.php/Java_gotchas#Immutable_Objects_.2F_Wrapper_Class_Caching


1
Grazie, questo spiega sicuramente perché 137 fallisce! E risponde anche alla mia domanda sul perché non si tratta di un problema prevalente, nel 95% dei casi che incontrerò, il valore sarebbe inferiore a 127. Buono a prenderlo ora anche se per il 5% dove non lo è.
Jeremy Goodell,

1
Nota a margine interessante: fino a un paio di settimane fa, cdiCt e cdsCt erano entrambi integri, quindi questo andava bene, ma ho dovuto renderli interi per verificare la situazione nulla che viene gestita in modo diverso ...
Jeremy Goodell

3
@Jeremy Sì, è un problema piuttosto oscuro, ma come regola generale usi .equals () per Oggetti e == per le primitive. Non puoi fare affidamento sull'autounboxing per i test di uguaglianza.
Adam,

1
Lol, segno di spunta a te allora! Sembra che Colin abbia già già abbastanza punti sufficienti.
Jeremy Goodell,

2
Nota che new Integer (1)! = New Integer (1) pure. new SEMPRE restituisce un nuovo indirizzo. Autoboxing utilizza una versione memorizzata nella cache. Altri modi che restituiscono numeri interi (senza modificarli) probabilmente restituiscono anche il valore memorizzato nella cache.
Bill K,

77

Non è possibile confrontare due Integercon un semplice ==sono gli oggetti, quindi il più delle volte i riferimenti non saranno gli stessi.

C'è un trucco, Integertra -128 e 127, i riferimenti saranno gli stessi degli usi di autoboxing Integer.valueOf()che memorizzano nella cache piccoli numeri interi.

Se il valore p in box è vero, falso, un byte, un carattere nell'intervallo da \ u0000 a \ u007f o un numero int o short tra -128 e 127, quindi lasciare che r1 e r2 siano i risultati di due conversioni di boxe di p. È sempre il caso che r1 == r2.


Risorse:

Sullo stesso argomento:


1
La garanzia è fornita da JLS o solo per Oracle JVM?
Thorbjørn Ravn Andersen,

La parte citata è della JLS, quindi è una garanzia della JLS
Colin Hebert,

Ri: garanzia. Non ci farei ancora troppo affidamento. new Integer(1) == new Integer(1)è ancora falso.
Thilo,

@Thilo new ... == new ...è sempre false.
MC Emperor

2
@Thilo True, utilizzare sempre equals()quando si tratta di oggetti. Questa dovrebbe essere una delle prime cose che si dovrebbero sapere durante l'apprendimento di Java. A proposito, avrei indovinato che il costruttore di Integerera privato, cioè che le istanze venivano sempre create attraverso il valueOf()metodo. Ma vedo che il costruttore è pubblico.
MC Emperor

5

Il problema è che i tuoi due oggetti Integer sono proprio questi, oggetti. Non corrispondono perché stai confrontando i due riferimenti a oggetti, non i valori all'interno. Ovviamente .equalsviene sovrascritto per fornire un confronto di valori anziché un confronto di riferimento di oggetti.


Buona risposta, ma non spiega perché fallisce solo per 137.
Jeremy Goodell,

4

Integersi riferisce al riferimento, ovvero quando si confrontano i riferimenti che si stanno confrontando se puntano allo stesso oggetto, non al valore. Quindi, il problema che stai vedendo. Il motivo per cui funziona così bene con i inttipi semplici è che decomprime il valore contenuto da Integer.

Posso aggiungere che se stai facendo quello che stai facendo, perché ifiniziare la frase?

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

4

"==" confronta sempre la posizione della memoria o i riferimenti agli oggetti dei valori. Il metodo equals confronta sempre i valori. Ma uguale utilizza indirettamente anche l'operatore "==" per confrontare i valori.

Integer utilizza la cache Integer per memorizzare i valori da -128 a +127. Se l'operatore == viene utilizzato per verificare la presenza di valori compresi tra -128 e 127, restituisce true. per diversi da questi valori restituisce false.

Fare riferimento al collegamento per alcune informazioni aggiuntive


1

Inoltre, per la correttezza dell'uso ==, puoi semplicemente decomprimere uno dei Integervalori confrontati prima di fare un ==confronto, come:

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

Il secondo verrà automaticamente decompresso (ovviamente devi nullprima verificare la presenza di messaggi di posta elettronica).


0

Oltre a queste ottime risposte, quello che ho imparato è che:

MAI confrontare oggetti con == a meno che tu non intenda confrontarli con i loro riferimenti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.