2009-11-09 11 views
120
class D { 
    public static void main(String args[]) { 
     Integer b2=128; 
     Integer b3=128; 
     System.out.println(b2==b3); 
    } 
} 

Salida:¿Por qué 128 == 128 devuelve falso pero 127 == 127 devuelve verdadero al convertir a envoltorios de enteros?

false 

class D { 
    public static void main(String args[]) { 
     Integer b2=127; 
     Integer b3=127; 
     System.out.println(b2==b3); 
    } 
} 

Salida:

true 

Nota: Los números entre -128 y 127 son verdaderas.

+10

Usted puede encontrar http://bexhuff.com/2006/11/java-1-5-autoboxing-wackyness informativo. –

+1

¿cómo llegaste al punto de hacer esta pregunta? es muy divertido, pero uno nunca se encuentra con algo así "en el mundo real" ... ¿o? –

+0

http://stackoverflow.com/a/11882284/57695 –

Respuesta

167

Cuando se compila un número literal en Java y la asigna a un entero (capital I) el compilador emite:

Integer b2 =Integer.valueOf(127) 

Esta línea de código también se genera cuando se utiliza autoboxing.

valueOf se implementa de tal manera que ciertos números se "combinaron", y se devuelve la misma instancia para valores más pequeños que 128.

A partir del código fuente de Java 1.6, la línea 621:

public static Integer valueOf(int i) { 
    if(i >= -128 && i <= IntegerCache.high) 
     return IntegerCache.cache[i + 128]; 
    else 
     return new Integer(i); 
} 

El el valor de high se puede configurar a otro valor, con la propiedad del sistema.

-Djava.lang.Integer.IntegerCache.high = 999

Si ejecuta su programa con que la propiedad del sistema, lo hará verdadera salida!

La conclusión obvia: nunca confíe en que dos referencias sean idénticas, siempre compárelas con el método .equals().

De modo que b2.equals(b3) se imprimirá verdadero para todos los valores lógicamente iguales de b2, b3.

Tenga en cuenta que la caché de enteros no está allí por motivos de rendimiento, sino que se comporta en el JLS, section 5.1.7; la identidad del objeto debe darse para los valores -128 a 127 inclusive.

Integer#valueOf(int) documentos también este comportamiento:

este método es probable que el rendimiento significativamente mejor rendimiento de espacio y tiempo al almacenar en caché los valores solicitados con frecuencia. Este método siempre almacenará en caché los valores en el rango -128 a 127, inclusive, y puede almacenar en caché otros valores fuera de este rango.

+1

tenga en cuenta que los valores menores que 127 serán ignorados por java y los valores mayores que Integer.MAX_VALUE-128 tendrá un límite. –

+0

Los enteros se almacenan en caché para valores de bytes en Java 5 y superior, lo que hace que el nuevo entero (1) == nuevo entero (1). Sin embargo, este no es el caso en Java 1.4 o inferior, así que ten cuidado si tienes que bajar de categoría a ese entorno. – MetroidFan2002

+10

no, esto está mal. nuevo entero (1) == nuevo entero (1) es falso independientemente de jvm. AFAIK ningún compilador hará trampa con la palabra clave "nueva". DEBE siempre instanciar un nuevo objeto. –

19

Cajas de Autoboxing -128 a 127. Esto se especifica en el JLS (5.1.7).

Si el valor pestá encajonado 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 el resultado de dos conversiones de boxeo de p. Siempre es el caso que r1 == r2.

Una simple regla a tener en cuenta cuando se trata de objetos es - .equals uso si usted quiere comprobar si los dos objetos son "iguales", el uso == cuando se quiere ver si apuntan a la misma instancia .

8

El uso de tipos de datos primitivos, ints, produciría verdadero en ambos casos, el resultado esperado.

Sin embargo, como está utilizando objetos enteros, el operador == tiene un significado diferente.

En el contexto de objetos, == comprueba si las variables se refieren a la misma referencia de objeto.

Para comparar el valor de los objetos, debe usar el método equals() E.g.

b2.equals(b1) 

que indicará si b2 es menor que b1, mayor que, o igual a (comprobar la API para los detalles)

-4

I escribió el siguiente ya que este problema no es sólo específico para Integer. Mi conclusión es que, en la mayoría de los casos, si utiliza la API incorrectamente, verá un comportamiento incorrecto. Utilizarlo correctamente y debería ver el comportamiento correcto:

public static void main (String[] args) { 
    Byte b1=127; 
    Byte b2=127; 

    Short s1=127; //incorrect should use Byte 
    Short s2=127; //incorrect should use Byte 
    Short s3=128; 
    Short s4=128; 

    Integer i1=127; //incorrect should use Byte 
    Integer i2=127; //incorrect should use Byte 
    Integer i3=128; 
    Integer i4=128; 

    Integer i5=32767; //incorrect should use Short 
    Integer i6=32767; //incorrect should use Short 

    Long l1=127L;   //incorrect should use Byte 
    Long l2=127L;   //incorrect should use Byte 
    Long l3=13267L;   //incorrect should use Short 
    Long l4=32767L;   //incorrect should use Short 
    Long l5=2147483647L; //incorrect should use Integer 
    Long l6=2147483647L; //incorrect should use Integer 
    Long l7=2147483648L; 
    Long l8=2147483648L; 

    System.out.print(b1==b2); //true (incorrect) Used API correctly 
    System.out.print(s1==s2); //true (incorrect) Used API incorrectly 
    System.out.print(i1==i2); //true (incorrect) Used API incorrectly 
    System.out.print(l1==l2); //true (incorrect) Used API incorrectly 

    System.out.print(s3==s4); //false (correct) Used API correctly 
    System.out.print(i3==i4); //false (correct) Used API correctly 
    System.out.print(i5==i6); //false (correct) Used API correctly 
    System.out.print(l3==l4); //false (correct) Used API correctly 
    System.out.print(l7==l8); //false (correct) Used API correctly 
    System.out.print(l5==l6); //false (correct) Used API incorrectly 

} 
2

Tener un vistazo a la Integer.java, si el valor se encuentra entre -128 y 127, que utilizará la piscina en caché, por lo (Integer) 1 == (Integer) 1 mientras (Integer) 222 != (Integer) 222

/** 
* Returns an {@code Integer} instance representing the specified 
* {@code int} value. If a new {@code Integer} instance is not 
* required, this method should generally be used in preference to 
* the constructor {@link #Integer(int)}, as this method is likely 
* to yield significantly better space and time performance by 
* caching frequently requested values. 
* 
* This method will always cache values in the range -128 to 127, 
* inclusive, and may cache other values outside of this range. 
* 
* @param i an {@code int} value. 
* @return an {@code Integer} instance representing {@code i}. 
* @since 1.5 
*/ 
public static Integer valueOf(int i) { 
    assert IntegerCache.high >= 127; 
    if (i >= IntegerCache.low && i <= IntegerCache.high) 
     return IntegerCache.cache[i + (-IntegerCache.low)]; 
    return new Integer(i); 
}  
4

Optimización de memoria en Java.

Para guardar en la memoria, todos los objetos envolventes 'reutiliza' Java cuyos valores caída en las siguientes gamas:

Todos los valores booleanos (verdadero y falso)

Todo Byte valores

Todos los valores de caracteres desde \ u0000 hasta \ u007f (es decir, de 0 a 127 en decimal)

Todos los valores abreviado y entero de -128 a 127.

Nota:

  • si crea booleana con new Boolean (valor); siempre obtendrá nuevo objeto

  • si crea Cadena con nueva Cadena (valor); siempre obtendrá nuevo objeto

  • si crea Entero con nuevo Entero (valor); siempre obtendrá nuevo objeto

etc.

Cuestiones relacionadas