web-dev-qa-db-fra.com

Combien d'objets sont créés à l'aide de la classe wrapper Integer?

Integer i = 3; 
i = i + 1; 
Integer j = i; 
j = i + j; 

Combien d'objets sont créés à la suite des instructions de l'exemple de code ci-dessus et pourquoi? Existe-t-il des IDE dans lesquels nous pouvons voir combien d'objets sont créés (peut-être en mode débogage)?

59
Syamesh K

Étonnamment, la réponse est zéro.

Tous les Integer de -128 à +127 sont pré-calculés par la JVM.

Votre code crée références à ces existants objets.

101
Bathsheba

La réponse strictement correcte est que le nombre d'objets Integer créés est indéterminé . Il peut être compris entre 0 et 3, ou 2561 ou encore plus2, cela dépend de

  • la plate-forme Java3,
  • si c'est la première fois que ce code est exécuté, et
  • (potentiellement) si un autre code qui repose sur la boxe des valeurs int s'exécute avant4.

Les valeurs de Integer pour -128 à 127 ne sont pas strictement requises pour être précalculées . En fait, JLS 5.1.7 qui a spécifié la conversion de boxe dit ceci:

Si la valeur p encadrée est un littéral entier de type int entre -128 et 127 inclus (§3.10.1) ... alors soit a et b le résultat de deux conversions boxing de p. Il est toujours vrai que a == b.

Deux choses à noter:

  • Le JLS uniquement nécessite ceci pour les >> littéraux <<.
  • Le JLS n'impose pas une mise en cache désirée des valeurs. La mise en cache paresseuse satisfait également les exigences comportementales du JLS.

Même le javadoc pour Integer.valueof(int) ne spécifie pas que les résultats sont mis en cache avec impatience.

Si nous examinons le Java SE pour Java.lang.Integer de Java 6 à 8, il est clair que la stratégie d'implémentation actuelle de Java SE consiste à précalculer les valeurs. Cependant, pour diverses raisons (voir ci-dessus) ), cela ne suffit pas encore pour donner une réponse définitive à la question "combien d'objets".


1 - Il pourrait être 256 si l'exécution du code ci-dessus déclenche l'initialisation de la classe pour Integer dans une version de Java où le cache est initialisé avec impatience pendant l'initialisation de la classe.

2 - Cela pourrait être encore plus, si le cache est plus grand que la spécification JVM l'exige. La taille du cache peut être augmentée via une option JVM dans certaines versions de Java.

3 - En plus de l'approche générale de la plate-forme pour implémenter la boxe, un compilateur pourrait repérer qu'une partie ou la totalité du calcul pourrait être fait au moment de la compilation ou l'optimiser complètement.

4 - Un tel code pourrait déclencher une initialisation paresseuse ou désirée du cache d'entiers.

60
Stephen C

Tout d'abord: la réponse que vous recherchez est 0, Comme d'autres l'ont déjà mentionné.

Mais allons un peu plus loin. Comme Stephen l'a mentionné, cela dépend du moment où vous l'exécutez. Parce que le cache est en fait initialisé paresseux.

Si vous regardez la documentation de Java.lang.Integer.IntegerCache:

Le cache est initialisé lors de la première utilisation.

Cela signifie que si c'est la première fois que vous appelez un entier, vous créez réellement:

  • 256 objets entiers (ou plus: voir ci-dessous)
  • 1 objet pour le tableau pour stocker les entiers
  • Ignorons les objets nécessaires pour stocker la classe (et les méthodes/champs). Ils sont de toute façon stockés dans la métaspace.

À partir de la deuxième fois que vous les appelez, vous créez 0 objets.


Les choses deviennent plus drôles une fois que les chiffres sont un peu plus élevés. Par exemple. par l'exemple suivant:

Integer i = 1500; 

Les options valides sont les suivantes: 0, 1 ou tout nombre compris entre 1629 et 2147483776 (cette fois uniquement en comptant les valeurs entières créées. Pourquoi? La réponse est donnée dans la phrase suivante de la définition du cache entier:

La taille du cache peut être contrôlée par l'option -XX: AutoBoxCacheMax =.

Vous pouvez donc réellement faire varier la taille du cache qui est implémenté.

Ce qui signifie que vous pouvez atteindre la ligne ci-dessus:

  • 1: nouvel objet si votre cache est inférieur à 1500
  • 0: nouveaux objets si votre cache a déjà été initialisé et contient 1500
  • 1629: nouveau (Entier) - Objets si votre cache est défini sur exactement 1500 et n'a pas encore été initialisé. Ensuite, des valeurs entières de -128 à 1500 seront créées.
  • Comme dans la phrase ci-dessus, vous atteignez n'importe quelle quantité d'objets entiers ici jusqu'à: Integer.MAX_VALUE + 129, qui est le mentionné: 2147483776.

Gardez à l'esprit: Ceci n'est garanti que sur Oracle/Open JDK (j'ai vérifié les versions 7 et 8)

Comme vous pouvez le voir, la réponse complètement correcte n'est pas si facile à obtenir. Mais dire simplement 0 Rendra les gens heureux.


PS: l'utilisation du paramètre menthoned peut rendre la déclaration suivante vraie: Integer.valueOf(1500) == 1500

17
Denis Lukenich

Le compilateur décompresse les objets Integer vers ints pour faire de l'arithmétique avec eux en appelant intValue() sur eux, et il appelle Integer.valueOf pour encadrer les résultats int lorsqu'ils sont affectés à des variables Integer, donc votre exemple équivaut à:

Integer i = Integer.valueOf(3);
i = Integer.valueOf(i.intValue() + 1);
Integer j = i;
j = Integer.valueOf(i.intValue() + j.intValue());

La tâche j = i; est une affectation de référence d'objet tout à fait normale qui ne crée aucun nouvel objet. Il ne fait ni boxing ni unboxing, et n'a pas besoin que les objets Integer soient immuables.

La méthode valueOf est autorisée à mettre en cache des objets et à renvoyer la même instance à chaque fois pour un nombre particulier. C'est requis pour mettre en cache les entrées −128 à +127. Pour votre numéro de départ de i = 3, tous les nombres sont petits et garantis pour être mis en cache, donc le nombre d'objets à créer est 0 . À strictement parler, valueOf est autorisé à mettre en cache des instances paresseusement plutôt que de les avoir toutes pré-générées, de sorte que l'exemple peut toujours créer des objets la première fois, mais si le code est exécuté à plusieurs reprises pendant un programme, le nombre d'objets créés à chaque fois en moyenne approche 0.

Que faire si vous commencez avec un plus grand nombre dont les instances ne seront pas mises en cache (par exemple, i = 300)? Ensuite, chaque appel valueOf doit créer un nouvel objet Integer, et le nombre total d'objets créés à chaque fois est 3 .

( Ou, c'est peut-être toujours zéro, ou peut-être des millions. N'oubliez pas que les compilateurs et les machines virtuelles sont autorisés à réécrire du code pour des raisons de performances ou d'implémentation, tant que son comportement n'est pas modifié par ailleurs. Il pourrait donc supprimer entièrement le code ci-dessus si vous ne utilisez le résultat. Ou si vous essayez d'imprimer j, il pourrait se rendre compte que j se terminera toujours avec la même valeur constante après l'extrait ci-dessus, et fera ainsi toute l'arithmétique au moment de la compilation, et imprimera un valeur constante. La quantité réelle de travail effectuée en arrière-plan pour exécuter votre code est toujours un détail d'implémentation.)

5
Boann

Vous pouvez déboguer la méthode Integer.valueOf (int i) pour le découvrir par vous-même. Cette méthode est appelée par le processus d'autoboxing par le compilateur.

2
Cootri