Je viens de voir du code similaire à celui-ci:
public class Scratch
{
public static void main(String[] args)
{
Integer a = 1000, b = 1000;
System.out.println(a == b);
Integer c = 100, d = 100;
System.out.println(c == d);
}
}
Lorsqu'il est exécuté, ce bloc de code imprimera:
false
true
Je comprends pourquoi le premier est false
: parce que les deux objets sont des objets séparés, donc le ==
compare les références. Mais je ne peux pas comprendre, pourquoi la deuxième déclaration revient-elle true
? Existe-t-il une étrange règle de mise en boîte automatique qui intervient lorsque la valeur d'un entier est dans une certaine plage? Que se passe t-il ici?
java
autoboxing
Joël
la source
la source
Réponses:
La
true
ligne est en fait garantie par la spécification du langage. De la section 5.1.7 :La discussion se poursuit, suggérant que bien que votre deuxième ligne de sortie soit garantie, la première ne l'est pas (voir le dernier paragraphe cité ci-dessous):
la source
valueOf
méthode de la classe box (commeInteger.valueOf(int)
). Il est intéressant de noter que le JLS définit le désugarage exact de déballage - en utilisantintValue()
et al - mais pas le désuétisme de boxe.Integer
que via l'public
API officielle , c'est-à-dire en appelantintValue()
. Mais il existe d'autres moyens possibles d'obtenir uneInteger
instance pour uneint
valeur, par exemple un compilateur peut générer du code en conservant et en réutilisant desInteger
instances précédemment créées .Production:
Oui, la première sortie est produite pour comparer la référence; «a» et «b» - ce sont deux références différentes. Au point 1, en fait, deux références sont créées, ce qui est similaire à -
La deuxième sortie est produite parce que le
JVM
essaie d'économiser de la mémoire, lorsque leInteger
tombe dans une plage (de -128 à 127). Au point 2, aucune nouvelle référence de type Integer n'est créée pour 'd'. Au lieu de créer un nouvel objet pour la variable de référence de type Integer 'd', il n'est affecté qu'à l'objet créé précédemment référencé par 'c'. Tout cela est fait parJVM
.Ces règles d'économie de mémoire ne s'appliquent pas uniquement à Integer. à des fins d'économie de mémoire, deux instances des objets wrapper suivants (lors de leur création par boxing), seront toujours == où leurs valeurs primitives sont les mêmes -
\u007f
(7f est 127 en décimal)la source
Long
a également un cache avec la même plage queInteger
.Les objets entiers dans une certaine plage (je pense que peut-être -128 à 127) sont mis en cache et réutilisés. Les entiers en dehors de cette plage reçoivent un nouvel objet à chaque fois.
la source
java.lang.Integer.IntegerCache.high
property. Intéressant que Long n'ait pas cette option.Oui, il existe une étrange règle de mise en boîte automatique qui intervient lorsque les valeurs sont dans une certaine plage. Lorsque vous affectez une constante à une variable Object, rien dans la définition du langage n'indique qu'un nouvel objet doit être créé. Il peut réutiliser un objet existant du cache.
En fait, la JVM stockera généralement un cache de petits entiers à cette fin, ainsi que des valeurs telles que Boolean.TRUE et Boolean.FALSE.
la source
Je suppose que Java garde un cache de petits entiers qui sont déjà `` encadrés '' parce qu'ils sont très courants et que cela permet de gagner beaucoup de temps pour réutiliser un objet existant plutôt que pour en créer un nouveau.
la source
C'est un point intéressant. Dans le livre, Effective Java suggère de toujours remplacer les égaux pour vos propres classes. De plus, pour vérifier l'égalité de deux instances d'objet d'une classe java, utilisez toujours la méthode equals.
Retour:
la source
En Java, la boxe fonctionne dans la plage comprise entre -128 et 127 pour un entier. Lorsque vous utilisez des nombres dans cette plage, vous pouvez le comparer avec l'opérateur ==. Pour les objets Integer en dehors de la plage, vous devez utiliser égal.
la source
L'affectation directe d'un littéral int à une référence Integer est un exemple d'auto-boxing, où la valeur littérale en code de conversion d'objet est gérée par le compilateur.
Ainsi, pendant la phase de compilation, le compilateur se convertit
Integer a = 1000, b = 1000;
enInteger a = Integer.valueOf(1000), b = Integer.valueOf(1000);
.C'est donc la
Integer.valueOf()
méthode qui nous donne en fait les objets entiers, et si nous regardons le code source de laInteger.valueOf()
méthode, nous pouvons clairement voir que la méthode met en cache les objets entiers dans la plage -128 à 127 (inclus).Ainsi, au lieu de créer et de renvoyer de nouveaux objets entiers,
Integer.valueOf()
la méthode renvoie des objets Integer à partir de l'interneIntegerCache
si le littéral int passé est supérieur à -128 et inférieur à 127.Java met en cache ces objets entiers car cette plage d'entiers est beaucoup utilisée dans la programmation quotidienne, ce qui économise indirectement de la mémoire.
Le cache est initialisé à la première utilisation lorsque la classe est chargée en mémoire à cause du bloc statique. La plage maximale du cache peut être contrôlée par l'
-XX:AutoBoxCacheMax
option JVM.Ce comportement de mise en cache n'est pas applicable uniquement aux objets Integer, similaire à Integer.IntegerCache que nous avons également
ByteCache, ShortCache, LongCache, CharacterCache
pourByte, Short, Long, Character
respectivement.Vous pouvez en savoir plus sur mon article Java Integer Cache - Why Integer.valueOf (127) == Integer.valueOf (127) Is True .
la source
Dans Java 5, une nouvelle fonctionnalité a été introduite pour économiser la mémoire et améliorer les performances des manipulations d'objets de type Integer. Les objets entiers sont mis en cache en interne et réutilisés via les mêmes objets référencés.
Cela s'applique aux valeurs entières comprises entre –127 et +127 (valeur entière max).
Cette mise en cache Integer ne fonctionne que sur l'auto-box. Les objets entiers ne seront pas mis en cache lorsqu'ils sont construits à l'aide du constructeur.
Pour plus de détails, veuillez consulter le lien ci-dessous:
Cache d'entiers en détail
la source
Si nous vérifions le code source de
Integer
obeject, nous trouverons la source de lavalueOf
méthode comme ceci:ce qui peut expliquer pourquoi les
Integer
objets, qui dans la plage de -128 (Integer.low
) à 127 (Integer.high
), sont les mêmes objets référencés pendant l'autoboxing. Et nous pouvons voir qu'une classeIntegerCache
s'occupe duInteger
tableau de cache, qui est une classe interne statique privée de laInteger
classe.Il y a un autre exemple intéressant qui peut nous aider à comprendre cette situation étrange:
la source