java - programacion - ¿Por qué el comportamiento del conjunto constante de números enteros cambia a 127?
manual de programacion android pdf (4)
En resumen, las versiones más recientes de caché de Java Integer están en el rango de -128 a 127 (256 valores). mira aquí
No puedo entender cómo funciona Java Constant Pool for Integer.
Entiendo el comportamiento de Strings, y por lo tanto puedo justificarme a mí mismo que es el mismo caso con constantes enteras también.
Entonces, para enteros
Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1==i2); // True
&
Integer i1 = new Integer(127);
Integer i2 = new Integer(127);
System.out.println(i1==i2); // False
Hasta aquí todo va en mi cabeza.
Lo que no puedo digerir es que se comporta de manera diferente cuando aumento el entero de 127. Este comportamiento cambia después de 127, a continuación se muestra el fragmento de código
Integer i1 = 128;
Integer i2 = 128;
System.out.println(i1==i2); // False. WHY?????
¿Alguien puede ayudarme a entender esto?
Java almacena en caché los objetos enteros en el rango -128 to 127
. Por lo tanto, cuando intenta asignar un valor en este rango a un objeto wrapper
, la operación de boxing
invocará el método Integer.valueOf
y, a su vez, asignará una referencia al objeto que ya está en el grupo.
Por otro lado, si asigna un valor fuera de este rango a un tipo de referencia de wrapper
, Integer.valueOf
creará un nuevo objeto Integer
para ese valor. Y, por lo tanto, al comparar la reference
para los objetos Integer
que tienen un valor fuera de este rango, obtendrás información false
Asi que,
Integer i = 127; --> // Equivalent to `Integer.valueOf(127)`
Integer i2 = 127;
// Equivalent to `Integer.valueOf(128)`
// returns `new Integer(128)` for value outside the `Range - [-128, 127]`
Integer i3 = 128;
Integer i4 = 128;
System.out.println(i == i2); // true, reference pointing to same literal
System.out.println(i3 == i4); // false, reference pointing to different objects
Pero cuando crea sus instancias de enteros utilizando un new
operador, se creará un nuevo objeto en Heap. Asi que,
Integer i = new Integer(127);
Integer i2 = new Integer(127);
System.out.println(i == i2); // false
Java mantiene el conjunto de enteros de -128
a 127
Declarar enteros como a continuación
Integer i1 = 127;
Resultados en
Integer i1 = Integer.valueOf(127);
Entonces, ¿qué está sucediendo realmente en el primer caso?
Integer i1 = 127;<---Integer.valueOf(127);
Integer i2 = 127;<---Integer.valueOf(127);<---Same reference as first
Desde el código fuente de Integer
para el método valueOf
clase
public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}
Entonces obtienes la misma referencia si el valor está entre -128
a 127
y llamas a valueOf
else devuelve un new Integer(i)
Y como la referencia es la misma, su ==
operador funciona para enteros devueltos por valueOf
entre este rango.
No, el grupo constante para números no funciona de la misma manera que para cadenas. Para las cadenas, solo las constantes de tiempo de compilación se internan, mientras que para los tipos de contenedor para los tipos de entero, cualquier operación de boxeo siempre usará el grupo si es aplicable para ese valor. Así por ejemplo:
int x = 10;
int y = x + 1;
Integer z = y; // Not a compile-time constant!
Integer constant = 11;
System.out.println(z == constant); // true; reference comparison
JLS garantiza una pequeña gama de valores agrupados, pero las implementaciones pueden usar un rango más amplio si lo desean.
Tenga en cuenta que, aunque no está garantizado, todas las implementaciones que he utilizado utilizan Integer.valueOf
para realizar operaciones de boxeo, por lo que puede obtener el mismo efecto sin la ayuda del idioma:
Integer x = Integer.valueOf(100);
Integer y = Integer.valueOf(100);
System.out.println(x == y); // true
De la sección 5.1.7 de JLS :
Si el valor p que aparece en la casilla es verdadero, falso, un byte o un carácter en el rango de / u0000 a / u007f, o un número entero o corto entre -128 y 127 (inclusive), entonces r1 y r2 son el resultado de dos conversiones de boxeo de p. Siempre es el caso que r1 == r2.
Idealmente, encajonar un valor primitivo p dado, 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 garantiza que, en la mayoría de los casos, 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.