Perché il comportamento del pool Costante intero cambia a 127?

Non sono in grado di capire come funziona Java Constant Pool for Integer.

Comprendo il comportamento di Stringhe e quindi in grado di giustificarmi che è lo stesso caso anche con Integer Constants.

Quindi, per Integers

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 

Fino a qui tutto mi passa per la testa.

Quello che non sono in grado di digerire è che si comporta diversamente quando aumento il numero intero da 127. Questo comportamento cambia dopo 127, di seguito c’è lo snippet di codice

 Integer i1 = 128; Integer i2 = 128; System.out.println(i1==i2); // False. WHY????? 

Qualcuno può aiutarmi a capirlo?

No, il pool costante per i numeri non funziona allo stesso modo delle stringhe. Per le stringhe, solo le costanti di compilazione sono internate, mentre per i tipi di wrapper per i tipi interi, qualsiasi operazione di boxing utilizzerà sempre il pool se è applicabile per quel valore. Quindi per esempio:

 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 

Il JLS garantisce una piccola gamma di valori raggruppati, ma le implementazioni possono utilizzare un intervallo più ampio se lo desiderano.

Nota che, sebbene non sia garantito, ogni implementazione che ho visto utilizza Integer.valueOf per eseguire operazioni di boxe – in modo da poter ottenere lo stesso effetto senza l’aiuto della lingua:

 Integer x = Integer.valueOf(100); Integer y = Integer.valueOf(100); System.out.println(x == y); // true 

Dalla sezione 5.1.7 della JLS :

Se il valore p in box è true, false, un byte o un char nell’intervallo da \ u0000 a \ u007f o un numero int o short compreso tra -128 e 127 (inclusi), quindi r1 e r2 devono essere i risultati di ogni due conversioni di boxe di p. È sempre il caso che r1 == r2.

Idealmente, inscatolare un dato valore primitivo p, darebbe sempre un riferimento identico. In pratica, questo potrebbe non essere fattibile utilizzando le tecniche di implementazione esistenti. Le regole di cui sopra sono un compromesso pragmatico. La clausola finale sopra richiede che determinati valori comuni siano sempre racchiusi in oggetti indistinguibili. L’implementazione può memorizzarli in cache, pigramente o impazientemente. Per altri valori, questa formulazione non ammette alcuna ipotesi sull’id quadro dei valori inseriti nella parte del programmatore. Ciò consentirebbe (ma non richiederà) la condivisione di alcuni o tutti questi riferimenti.

Ciò garantisce che, nei casi più comuni, il comportamento sia quello desiderato, senza imporre una penalità di prestazioni eccessive, specialmente su dispositivi di piccole dimensioni. Ad esempio, meno implementazioni a memoria limitata potrebbero memorizzare nella cache tutti i valori char e short, nonché i valori int e long nell’intervallo da -32K a +32K.

Java gestisce il pool intero da -128 a 127

Dichiarazione di numeri interi come di seguito

 Integer i1 = 127; 

Risultati in

 Integer i1 = Integer.valueOf(127); 

Quindi, ciò che effettivamente accade per il primo caso è

 Integer i1 = 127;<---Integer.valueOf(127); Integer i2 = 127;<---Integer.valueOf(127);<---Same reference as first 

Dal codice sorgente di Integer per il metodo valueOf class

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

Quindi ottieni lo stesso riferimento se il valore è -128 tra -128 e 127 e chiami valueOf altro restituisce appena il numero new Integer(i)

E poiché il riferimento è lo stesso, l'operatore == funziona per gli interi restituiti da valueOf tra questo intervallo.

Java memorizza nella cache gli oggetti interi nell’intervallo da -128 to 127 . Quindi, quando si tenta di assegnare un valore in questo intervallo a un object wrapper , l’operazione di boxing invocherà il metodo Integer.valueOf e a sua volta assegnerà un riferimento all’object già nel pool.

D’altra parte, se assegni un valore al di fuori di questo intervallo a un tipo di riferimento wrapper , Integer.valueOf creerà un nuovo object Integer per quel valore. E quindi, confrontare il reference per gli oggetti Integer che hanno valore al di fuori di questo intervallo ti darà false

Così,

 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 

Tuttavia, quando crei le istanze dei numeri interi utilizzando un new operatore, verrà creato un nuovo object su Heap. Così,

 Integer i = new Integer(127); Integer i2 = new Integer(127); System.out.println(i == i2); // false 

In breve versioni più recenti della cache Java Integer si trova nell’intervallo da -128 a 127 (256 valori). guarda qui

Che cosa fa esattamente il confronto degli interi con ==?