Je ne suis pas en mesure de comprendre comment fonctionne le Java Constant Pool for Integer).
Je comprends le comportement de Strings, et donc je peux me justifier que c'est également le cas avec les constantes entières.
Donc, pour les entiers
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
Jusqu'ici tout se passe dans ma tête.
Ce que je ne peux pas digérer, c'est qu'il se comporte différemment lorsque j'augmente l'entier à partir de 127. Ce comportement change après 127, ci-dessous est l'extrait de code
Integer i1 = 128;
Integer i2 = 128;
System.out.println(i1==i2); // False. WHY?????
Quelqu'un peut-il m'aider à comprendre cela?
Non, le pool constant de nombres ne fonctionne pas de la même manière que pour les chaînes. Pour les chaînes, seules les constantes au moment de la compilation sont internées - alors que pour les types d'encapsuleur pour les types entiers, toute opération de boxe utilisera toujours le pool s'il est applicable pour cette valeur. Ainsi, par exemple:
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
Le JLS garantit une petite plage de valeurs regroupées, mais les implémentations peuvent utiliser une plage plus large si elles le souhaitent.
Notez que bien que ce ne soit pas garanti, chaque implémentation que j'ai examinée utilise Integer.valueOf
pour effectuer des opérations de boxe - afin que vous puissiez obtenir le même effet sans l'aide de la langue:
Integer x = Integer.valueOf(100);
Integer y = Integer.valueOf(100);
System.out.println(x == y); // true
De section 5.1.7 du JLS :
Si la valeur p encadrée est vraie, fausse, un octet ou un caractère compris entre\u0000 et\u007f, ou un nombre entier ou court compris entre -128 et 127 (inclus), alors que r1 et r2 soient les résultats de deux conversions de boxe de p. Il est toujours vrai que r1 == r2.
Idéalement, encadrer une valeur primitive donnée p donnerait toujours une référence identique. En pratique, cela peut ne pas être possible en utilisant les techniques de mise en œuvre existantes. Les règles ci-dessus sont un compromis pragmatique. La dernière clause ci-dessus exige que certaines valeurs communes soient toujours encadrées dans des objets indiscernables. L'implémentation peut les mettre en cache, paresseusement ou avec empressement. Pour les autres valeurs, cette formulation interdit toute hypothèse sur l'identité des valeurs encadrées de la part du programmeur. Cela permettrait (mais n'exigerait pas) le partage de tout ou partie de ces références.
Cela garantit que dans la plupart des cas, le comportement sera celui souhaité, sans imposer de pénalité de performance indue, en particulier sur les petits appareils. Des implémentations moins limitées en mémoire peuvent, par exemple, mettre en cache toutes les valeurs char et short, ainsi que les valeurs int et long dans la plage de -32K à + 32K.
Java maintient le pool entier de -128
À 127
Déclarer un entier comme ci-dessous
Integer i1 = 127;
Résultats à
Integer i1 = Integer.valueOf(127);
Donc, ce qui se passe réellement pour le premier cas est
Integer i1 = 127;<---Integer.valueOf(127);
Integer i2 = 127;<---Integer.valueOf(127);<---Same reference as first
Du code source de Integer
pour la méthode classe valueOf
public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}
Ainsi, vous obtenez la même référence si la valeur est comprise entre -128
À 127
Et vous appelez valueOf
sinon il retourne simplement new Integer(i)
Et comme la référence est la même, votre opérateur ==
Fonctionne pour les entiers renvoyés par valueOf
entre cette plage.
Java met en cache les objets entiers dans la plage -128 to 127
. Ainsi, lorsque vous essayez d'affecter une valeur dans cette plage à un objet wrapper
, l'opération boxing
appellera Integer.valueOf
et à son tour, il assignera une référence à l'objet déjà dans le pool.
En revanche, si vous affectez une valeur en dehors de cette plage à un type de référence wrapper
, Integer.valueOf
créera un nouvel objet Integer
pour cette valeur. Et par conséquent, la comparaison des objets reference
pour Integer
ayant une valeur en dehors de cette plage vous donnera false
Alors,
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
Mais, lorsque vous créez vos instances entières à l'aide de l'opérateur new
, un nouvel objet sera créé sur le tas. Alors,
Integer i = new Integer(127);
Integer i2 = new Integer(127);
System.out.println(i == i2); // false
Dans les versions plus récentes de Java cache Integer est compris entre -128 et 127 (256 valeurs). Regardez ici
Que fait exactement la comparaison de nombres entiers avec ==?