Primitives Java et Wrappers Primitifs


J'essaie de comprendre comment fonctionnent les primitives et les wrappers Java. Considérons l'exemple suivant.

Integer sum = 0;
for(int i = 0; i < 10000; ++i) {
    sum += i;
}

Puisque Integer est immuable et non primitif, l'instruction {[2] } sera compilée comme suit

sum =  new Integer(sum.intValue() + i).

Cela créerait environ 10000 objets entiers (chaque appel à new Integer) et le coût de sum.intValue() de déballer l'entier en int.

Ai-je raison?

Author: Narendra Pathai, 2013-08-29

4 answers

Pas exactement. En fait:

    sum += i;

Est équivalent à

    sum = Integer.valueOf(sum.intValue() + i);

Pour les petites valeurs entières, Integer.valueOf(int) renverra un objet Integer mis en cache. Cela signifie que vous obtiendrez un peu moins de 10 000 nouveaux objets Integer créés.

Mais "petit" signifie généralement -128 à +127 (IIRC) ... donc, la différence ne sera pas significatif.


Comme le souligne Louis Wasserman,l'allocation d'objets est bon marché, et la collecte des ordures des objets qui "meurent jeunes" est encore moins chère. Néanmoins, vous ne devrait pas utiliser inutilement des wrappers primitifs, et surtout pas dans du code comme celui-ci.

 6
Author: Stephen C, 2013-08-29 05:41:26

Préférez les types primitifs aux types en boîte lors de l'utilisation de Loop

Oui, vous avez raison le processus de boxe et de déballage, en particulier dans une boucle peut sérieusement entraver les performances.

Mais dans votre cas, vous faites juste une boucle et vous devriez NE PAS utiliser une primitive en boîte ici et plutôt utiliser int

 2
Author: Narendra Pathai, 2013-08-29 05:10:52

Non ce n'est pas comme ça. L'opérateur d'affectation composé E1 op= E2 est équivalent à E1 = (T) ((E1) op (E2)), à la différence que E1 n'est évalué qu'une seule fois.

De la section JLS 15.26.2:

Une expression d'affectation composée de la forme E1 op= E2 est équivalente à E1 = (T) ((E1) op (E2)), où T est le type de E1, sauf que E1 n'est évalué qu'une seule fois.

Ainsi, une opération binaire est effectuée entre une référence entière et un type primitif. Où cas, la référence entière sera décompressée, et l'opération sera effectuée, et la valeur sera à nouveau mise en boîte à la référence Integer. À partir de JLS Section 5.6.2-Promotion numérique binaire:

Si un opérande est de type de référence, il est soumis à une conversion de déballage (§5.1.8).

Donc, non un nouvel objet entier n'est pas nécessairement créé. L'expression dans votre boucle est évaluée comme:

Integer sum = Integer.valueOf(sum.intValue() + i);

Et la méthode valueOf peuvent utiliser une valeur mise en cache de Integer objet(pour certains).


Cela dit, j'espère que vous n'utilisez pas littéralement un type wrapper comme celui-ci dans votre code d'origine, mais juste dans un but de compréhension. Vous n'avez pas besoin d'utiliser le type wrapper, sauf si vous en avez vraiment besoin, et ce serait un cas rare.

 2
Author: Rohit Jain, 2013-08-29 05:14:24

Oui, presque 10000. C'est un decomiled .classe

    Integer sum = Integer.valueOf(0);
    for(int i = 0; i < 10000; i++)
        sum = Integer.valueOf(sum.intValue() + i);

Entier.valueOf a un cache pour les petits nombres, -128 à 127 par défaut, donc en fait 10000 - 128 instances entières seront créées

 1
Author: Evgeniy Dorofeev, 2013-08-29 05:14:57