2010-09-03 23 views
106

A partir de Java 1.5, puede intercambiar casi Integer con int en muchas situaciones.Java: Entero es igual a ==

Sin embargo, encontré un defecto potencial 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 estableciendo de forma incorrecta desajuste cuando los valores son iguales, aunque no puedo determinar bajo qué circunstancias. Establecí un punto de interrupción en Eclipse y vi que los valores de Integer eran ambos 137, e inspeccioné la expresión booleana y decía que era falsa, pero cuando puse el pie sobre ella, estaba estableciendo la discrepancia en verdadero.

Cambio de la condicional a:

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

solucionado el problema.

¿Alguien puede arrojar algo de luz sobre por qué sucedió esto? Hasta ahora, solo he visto el comportamiento en mi localhost en mi propia PC. En este caso particular, el código logró superar las 20 comparaciones, pero falló en 2. El problema fue consistentemente reproducible.

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

¿Todavía no es legítimo usar == para comparar dos valores de Integer?

Además de todas las buenas respuestas a continuación, el siguiente enlace stackoverflow tiene bastante información adicional. En realidad, habría contestado a mi pregunta original, sino porque no he mencionado autoboxing en mi pregunta, no se mostrará en las sugerencias seleccionados:

Why can't the compiler/JVM just make autoboxing “just work”?

Respuesta

177

La JVM almacena en caché valores enteros. == sólo funciona para los números entre -128 y 127 http://www.owasp.org/index.php/Java_gotchas#Immutable_Objects_.2F_Wrapper_Class_Caching

+1

¡Gracias, eso sin duda explica por qué 137 falla! Y también responde mi pregunta acerca de por qué no es un problema frecuente, en el 95% de los casos que voy a encontrar, el valor sería inferior a 127. Sin embargo, es bueno captar esto ahora para el 5% donde no lo es. –

+0

Nota interesante: hasta hace un par de semanas, cdiCt y cdsCt eran dos enteros así que estaba bien, pero tuve que convertirlos en enteros para verificar la situación nula que se maneja de manera diferente ... –

+2

@Jeremy Sí, es un problema bastante oscuro, pero como regla general usas .equals() para Objects y == para primitives. No puede confiar en el autoenvío para pruebas de igualdad. – Adam

5

La cuestión 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 .equals se reemplaza para proporcionar una comparación de valores a diferencia de una comparación de referencia de objeto.

+0

Buena respuesta, pero no explica por qué no es sólo para 137. –

+0

Doh, echaba de menos esa parte. – MattC

4

Integer se refiere a la referencia, es decir, al comparar las 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 tipos simples int es que desagrupa el valor que contiene el Integer.

Puedo agregar que si estás haciendo lo que estás haciendo, ¿para qué empezar con la declaración if?

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

Buen punto, pero no estoy haciendo lo que estoy haciendo. Fue simplificado. –

+0

Así se debe escribir el código y esta debería ser la respuesta aceptada. ** Siempre ** compara objetos con .equals(). ¿Por qué utilizar los enteros en caché y dejar el código al azar? – NobleUplift

61

No se pueden comparar dos Integer con un simple == que son objetos para la mayoría de las referencias de tiempo no será el mismo.

Hay un truco, con Integer entre -128 y 127, las referencias serán las mismas que el autoboxing usa Integer.valueOf() que almacena en caché números enteros pequeños.

Si está encajonado el valor p es verdadero, falso, un byte, un char en el rango \ u0000 a \ u007f, o un int o número corto entre -128 y 127, entonces que R1 y R2 sea la resultados de dos conversiones de boxeo de p. Siempre es el caso que r1 == r2.


Recursos:

Sobre el mismo tema:

+0

Gracias, marqué la primera respuesta como la correcta. –

+0

oh, supongo que puedo marcarlos como correctos. Marca de verificación para usted también. –

+0

@Jeremy, en realidad solo puedes marcar uno como correcto. Al hacer clic en la marca de verificación una segunda vez, solo cambia la respuesta aceptada. No ser mezquino; La respuesta de Colin es excelente. :) – Adam

1

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

Entero utiliza la memoria caché 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 estos valores, devuelve falso.

remitir el link algo de información adicional