¿Por qué el comportamiento del conjunto constante de números enteros cambia a 127?

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?

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 comstackció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 progtwigdor. 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.

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.

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 

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í

¿Qué es exactamente la comparación de enteros con == do?