Java: entero es igual a vs ==

152

A partir de Java 1.5, se puede casi el intercambio Integercon inten muchas situaciones.

Sin embargo, encontré un posible defecto en mi código que me sorprendió un poco.

El siguiente código:

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

parecía estar configurando incorrectamente la falta de coincidencia cuando los valores eran iguales, aunque no puedo determinar en qué circunstancias. Establecí un punto de interrupción en Eclipse y vi que los Integervalores eran 137, e inspeccioné la expresión booleana y dijo que era falsa, pero cuando la pasé, estaba configurando la falta de coincidencia en verdadero.

Cambiar el condicional a:

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

Se solucionó el problema.

¿Alguien puede arrojar algo de luz sobre por qué sucedió esto? Hasta ahora, solo he visto el comportamiento en mi host local en mi propia PC. En este caso particular, el código superó con éxito unas 20 comparaciones, pero falló en 2. El problema fue reproducible de manera consistente.

Si es un problema frecuente, debería estar causando errores en nuestros otros entornos (desarrollo y prueba), pero hasta ahora, nadie ha informado el problema después de cientos de pruebas que ejecutan este fragmento de código.

¿Todavía no es legítimo usar ==para comparar dos Integervalores?

Además de todas las respuestas detalladas a continuación, el siguiente enlace stackoverflow tiene bastante información adicional. En realidad, habría respondido a mi pregunta original, pero como no mencioné el autoboxing en mi pregunta, no apareció en las sugerencias seleccionadas:

¿Por qué el compilador / JVM no puede hacer que el autoboxing "simplemente funcione"?

Jeremy Goodell
fuente

Respuestas:

238

La JVM está almacenando en caché valores enteros. == solo funciona para números entre -128 y 127 http://www.owasp.org/index.php/Java_gotchas#Immutable_Objects_.2F_Wrapper_Class_Caching

Adán
fuente
1
Gracias, eso ciertamente explica por qué 137 falla. Y también responde a mi pregunta sobre por qué no es un problema frecuente, en el 95% de los casos que voy a encontrar, el valor sería inferior a 127. Aunque es bueno captar esto ahora para el 5% donde no lo es.
Jeremy Goodell
1
Nota al margen interesante: hasta hace un par de semanas, cdiCt y cdsCt eran ambos entrantes, así que estaba bien, pero tuve que convertirlos en números enteros para verificar la situación nula que se maneja de manera diferente ...
Jeremy Goodell
3
@ Jeremy Sí, es un problema bastante oscuro, pero como regla general usas .equals () para Objetos y == para primitivas. No puede confiar en el autounboxing para las pruebas de igualdad.
Adam
1
Lol, marca de verificación de nuevo a ti entonces! Parece que Colin ya tiene puntos más que suficientes.
Jeremy Goodell
2
Tenga en cuenta que new Integer (1)! = New Integer (1) también. nuevo SIEMPRE devuelve una nueva dirección. Autoboxing utiliza una versión en caché. Otras formas que devuelven números enteros (sin renovarlos) probablemente también devuelvan el valor almacenado en caché.
Bill K
77

No puedes comparar dos Integercon un simple== objetos, por lo que la mayoría de las veces las referencias no serán las mismas.

Hay un truco, con Integerentre -128 y 127, las referencias serán las mismas que las del autoboxing Integer.valueOf()que almacena enteros pequeños.

Si el valor p encuadrado es verdadero, falso, un byte, un carácter en el rango de \ u0000 a \ u007f, o un número int o corto entre -128 y 127, entonces deje que r1 y r2 sean el resultado de dos conversiones de boxeo de p. Siempre es el caso de que r1 == r2.


Recursos:

Sobre el mismo tema:

Colin Hebert
fuente
1
¿Es la garantía de JLS o solo para Oracle JVM?
Thorbjørn Ravn Andersen
La parte citada es de JLS, por lo que es una garantía de JLS
Colin Hebert
Re: garantía. Todavía no confiaría demasiado en ello. new Integer(1) == new Integer(1)sigue siendo falso
Thilo
@Thilo new ... == new ...es siempre false.
MC Emperor
2
@Thilo True, siempre se usa equals()cuando se trata de objetos. Esta debería ser una de las primeras cosas que uno debe saber al aprender Java. Por cierto, habría adivinado que el constructor de Integerera privado, es decir, que las instancias siempre se creaban a través del valueOf()método. Pero veo que el constructor es público.
MC Emperor
5

El problema es que sus dos objetos Integer son solo eso, objetos. No coinciden porque está comparando sus dos referencias de objeto, no los valores dentro. Obviamente, .equalsse anula para proporcionar una comparación de valores en lugar de una comparación de referencia de objeto.

MattC
fuente
Buena respuesta, pero no explica por qué solo está fallando para 137.
Jeremy Goodell
4

Integerse refiere a la referencia, es decir, al comparar referencias que está comparando si apuntan al mismo objeto, no al valor. Por lo tanto, el problema que estás viendo. La razón por la que funciona tan bien con los inttipos simples es que desempaqueta el valor contenido en Integer.

¿Puedo agregar que si está haciendo lo que está haciendo, por qué tener la ifdeclaración para comenzar?

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

"==" siempre compara la ubicación de la memoria o las referencias a objetos de los valores. método igual siempre compara los valores. Pero igual también usa indirectamente el operador "==" para comparar los valores.

Integer utiliza la memoria caché de Integer para almacenar los valores de -128 a +127. Si el operador == se usa para verificar cualquier valor entre -128 a 127, entonces devuelve verdadero. para otros que no sean estos valores devuelve falso.

Consulte el enlace para obtener información adicional

vijay
fuente
1

Además de la exactitud del uso ==, puede desempaquetar uno de los Integervalores comparados antes de hacer la ==comparación, como:

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

El segundo se desempaquetará automáticamente (por supuesto, nullprimero debe verificar si hay s).

Mc Bton
fuente
0

Además de estas excelentes respuestas, lo que he aprendido es que:

NUNCA compare objetos con == a menos que tenga la intención de compararlos por sus referencias.

ZhaoGang
fuente