2012-04-03 27 views
24

Camina conmigo ..La comparación de valores enteros en Java, comportamiento extraño

Integer x = 23; 
Integer y = 23; 

if (x == y) 
    System.out.println("what else");  // All is well as expected 
else 
    System.out.println("..."); 

Mientras

Integer x = someObject.getIndex(); 
Integer y = someOtherObject.getSomeOtherIndex(); 

if (x == y) 
    System.out.println("what else"); 
else 
    System.out.println("...");  // Prints this 

Hmm ... Prueba a transmitir a int

int x = someObject.getIndex(); 
int y = someOtherObject.getSomeOtherIndex() 

if (x == y)  
    System.out.println("what else"); // works fine 
else 
    System.out.println("..."); 

Son tanto Enteros?

System.out.println(x.getClass().getName());    // java.lang.Integer 
System.out.println(y.getClass().getName());    // java.lang.Integer 
System.out.println(someObject.getIndex());    // java.lang.Integer 
System.out.println(someOtherObject.getSomeOtherIndex()); // java.lang.Integer 

¿Qué piensan ustedes? ¿Qué podría explicar algo como esto?

+0

posible duplicado de [Cómo operador = y == operador trabaja en Java ?] (http://stackoverflow.com/questions/9824053/how-operator-and-operator-works-in-java) – assylias

+0

¿Qué hacen 'getIndex();' y 'getSomeOtherIndex()' do? –

+0

Posible duplicado de [¿Por qué 128 == 128 devuelve falso pero 127 == 127 devuelve verdadero al convertir a envoltorios de entero?] (Https://stackoverflow.com/questions/1700081/why-does-128-128-return- false-pero-127-127-return-true-when-converting-to-integ) – Tom

Respuesta

42

Está comparando Integer valores, que son referencias. Usted viene con esas referencias a través de autoboxing. Para algunos valores (garantizados para -128 a 127), el JRE mantiene un caché de objetos Integer. Para valores más altos, no lo hace. De section 5.1.7 of the JLS:

Si el valor p de ser en caja es verdadero, falso, un byte o un caracter en el rango \ u0000 a \ u007f, o un int o número corto entre -128 y 127 (ambos inclusive), entonces, r1 y r2 sean los resultados de dos conversiones de boxeo cualquiera de p. Siempre es el caso que r1 == r2.

Idealmente, encajonar un valor primitivo dado p, siempre arrojaría una referencia idéntica. En la práctica, esto puede no ser factible utilizando las técnicas de implementación existentes. Las reglas anteriores son un compromiso pragmático. La cláusula final anterior requiere que ciertos valores comunes siempre estén enmarcados en objetos indistinguibles. La implementación puede almacenarlos en caché, de forma perezosa o ansiosa. Para otros valores, esta formulación no permite ninguna suposición sobre la identidad de los valores encuadrados por parte del programador. Esto permitiría (pero no requeriría) compartir algunas o todas estas referencias.

Esto asegura que en la mayoría de los casos comunes, el comportamiento será el deseado, sin imponer una penalización de rendimiento excesiva, especialmente en dispositivos pequeños. Las implementaciones menos limitadas de memoria podrían, por ejemplo, almacenar en caché todos los valores de char y cortos, así como los valores int y long en el rango de -32K a +32K.

Moral: no se pueden comparar Integer referencias cuando se está interesado en los int valores subyacentes. Use .equals() o obtenga los valores int primero.

+2

@JAM: Sí, ya sea para convertir a 'int', llamar a' intValue() 'y comparar los resultados, o llamar a' equals() '. –

+1

Ok, genial; Gracias Jon! – JAM

1

Suena como algo funky con auto-boxing cuando usa == en los dos enteros.

Supongo que funciona bien al usar Integer si utiliza el método equals()? Eso sería por mi suposición de todos modos.

No estás usando Java 1.4 o algo así?

+0

Las otras respuestas indican exactamente por qué sucede esto: la JVM almacena en caché valores pequeños de enteros. Entonces, cuando comparo (nuevo Integer (12) == new Integer (12)) [yields true] la JVM devuelve el MISMO objeto en caché para ambos lados de ese valor de 12. Entonces, de hecho, los objetos son los mismos. Para valores grandes, independientemente se crean nuevos objetos, y esto no sucede. – ingyhere

13

Para comparar los enteros correctamente, debe usar .equals() o comparar sus valores primitivos mediante conversión a int o llamando al intValue() en ellos.

Usando == comprueba si los dos números enteros son el mismo objeto, no si contienen el mismo valor numérico.

Integer a = new Integer(1); 
    Integer b = new Integer(1); 

    System.out.println(a.equals(b));     //true 
    System.out.println((int)a == (int)b);    //true 
    System.out.println(a.intValue() == b.intValue()); //true 
    System.out.println(a == b);      //false 

Editado para ilustrar el punto de Jon de la JLS sobre autoboxing:

Integer a = 1; 
    Integer b = 1; 
    System.out.println(a.equals(b));     //true 
    System.out.println((int)a == (int)b);    //true 
    System.out.println(a.intValue() == b.intValue()); //true 
    System.out.println(a == b);      //true 

frente:

Integer a = 128; 
    Integer b = 128; 
    System.out.println(a.equals(b));     //true 
    System.out.println((int)a == (int)b);    //true 
    System.out.println(a.intValue() == b.intValue()); //true 
    System.out.println(a == b);      //false