39 votes

Combien d'objets String seraient créés lors de la concaténation de plusieurs Strings ?

Lors d'un entretien, on m'a demandé le nombre d'objets qui seront créés pour un problème donné :

String str1 = "First";
String str2 = "Second";
String str3 = "Third";
String str4 = str1 + str2 + str3;

J'ai répondu qu'il y aurait 6 objets créés dans le pool de chaînes.

3 seraient pour chacune des trois variables.
1 serait pour str1 + str2 (disons str ).
1 serait pour str2 + str3 .
1 serait pour le str + str3 ( str = str1 + str2 ).

La réponse que j'ai donnée est-elle correcte ? Si non, quelle est la bonne réponse ?

35voto

Andrew Tobilko Points 1283

Toute réponse à votre question dépendra de l'implémentation de la JVM et de la version de Java actuellement utilisée. Je pense que c'est une question déraisonnable à poser lors d'un entretien.

Java 8

Sur ma machine, avec Java 1.8.0_201, votre extrait donne le résultat suivant en bytecode

L0
 LINENUMBER 13 L0
 LDC "First"
 ASTORE 1
L1
 LINENUMBER 14 L1
 LDC "Second"
 ASTORE 2
L2
 LINENUMBER 15 L2
 LDC "Third"
 ASTORE 3
L3
 LINENUMBER 16 L3
 NEW java/lang/StringBuilder
 DUP
 INVOKESPECIAL java/lang/StringBuilder.<init> ()V
 ALOAD 1
 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
 ALOAD 2
 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
 ALOAD 3
 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
 INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
 ASTORE 4

ce qui prouve que 5 objets sont en cours de création (3 String littéraux*, 1 StringBuilder 1 produit dynamiquement String instance par [StringBuilder#toString](https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/lang/CharSequence.html#toString()) ).

Java 12

Sur ma machine, avec Java 12.0.2, le bytecode est le suivant

// identical to the bytecode above
L3
 LINENUMBER 16 L3
 ALOAD 1
 ALOAD 2
 ALOAD 3
 INVOKEDYNAMIC makeConcatWithConstants(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; [
  // handle kind 0x6 : INVOKESTATIC
  java/lang/invoke/StringConcatFactory.makeConcatWithConstants(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
  // arguments:
  "\u0001\u0001\u0001"
 ]
 ASTORE 4

dont par magie change "la bonne réponse" en 4 objets puisqu'il n'y a pas d'intermédiaire StringBuilder impliqué.


*Devons creuser un peu plus profond.

12.5. Création de nouvelles instances de classe

Une nouvelle instance de classe peut être créée implicitement dans les situations suivantes :

  • Chargement d'une classe ou d'une interface qui contient un littéral de chaîne de caractères ( §3.10.5 ) peut créer un nouvel objet String pour représenter le littéral. (Cela ne se produira pas si une chaîne dénotant la même séquence de points de code Unicode a été internée précédemment).

En d'autres termes, lorsque vous démarrez une application, il y a déjà des objets dans le pool de cordes. Vous savez à peine ce qu'ils sont et d'où ils viennent (à moins que vous n'analysiez toutes les classes chargées pour trouver tous les littéraux qu'elles contiennent).

El java.lang.String sera indubitablement chargée comme une classe essentielle de la JVM, ce qui signifie que tous ses littéraux seront créés et placés dans le pool.

Prenons un extrait choisi au hasard dans le code source de String nous choisissons quelques littéraux, nous plaçons un point d'arrêt au tout début de notre programme et nous examinons si le pool contient ces littéraux.

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence,
               Constable, ConstantDesc {
    ...
    public String repeat(int count) {
        // ... 
        if (Integer.MAX_VALUE / count < len) {
            throw new OutOfMemoryError("Repeating " + len + " bytes String " + count +
                    " times will produce a String exceeding maximum size.");
        }
    }
    ...
}

Ils sont là en effet.

Fait intéressant, le filtrage de cet IDEA a un effet secondaire : les sous-chaînes que je recherchais ont également été ajoutées au pool. La taille du pool a augmenté de un ( "bytes String" a été ajouté) après avoir appliqué this.contains("bytes String") .

Où cela nous mène-t-il ?

Nous n'avons aucune idée si "First" a été créé et interné avant que nous appelions String str1 = "First"; Nous ne pouvons donc pas affirmer avec certitude que la ligne crée une nouvelle instance.

19voto

Turing85 Points 5992

Avec les informations données, on ne peut pas répondre définitivement à la question. Comme il est indiqué dans le JLS, §15.18.1 :

... Pour augmenter les performances de la concaténation répétée de chaînes de caractères, un compilateur Java peut utiliser l'attribut StringBuffer ou une technique similaire pour réduire le nombre d'objets String intermédiaires créés par l'évaluation d'une expression.

Cela signifie que la réponse dépend au moins du compilateur Java concret utilisé.

Je pense que le mieux que l'on puisse faire est de donner un intervalle comme réponse :

  • un compilateur intelligent peut être capable de déduire que str1 a str3 ne sont jamais utilisées et replient la concaténation lors de la compilation, de sorte qu'une seule String -est créé (celui qui est référencé par la commande str4 )
  • Le nombre maximal raisonnable de String créés devraient être au nombre de 5 : un pour chaque str1 a str3 un pour tmp = str1 + str2 et un pour str4 = tmp + str3 .

Donc... ma réponse serait "quelque chose entre un et cinq". String -objets". Quant au nombre total d'objets créés juste pour cette opération... Je n'en sais rien. Cela peut aussi dépendre de la façon dont, par exemple, on peut créer un objet. StringBuffer est mis en œuvre.

En passant, je me demande quelle est la raison pour laquelle on pose de telles questions. Normalement, il n'est pas nécessaire de se soucier de ces détails.

9voto

Puce Points 13540

Java 8 créera probablement 5 objets :

  • 3 pour les 3 littéraux
  • 1 StringBuilder
  • 1 pour la concaténation String

Avec Java 9 les choses ont changé cependant et String La concaténation n'utilise pas StringBuilder plus.

3voto

Laurenz Albe Points 40920

Il devrait être de 5 :

  • trois pour les trois littéraux (affectés à str1 , str2 y str3 )

  • un pour str1 + str2

  • un pour (result from the previous operation) + str3 (affecté à str4 )

3voto

Boann Points 11904

Une implémentation Java conforme peut concaténer les chaînes de plusieurs façons, au moment de l'exécution ou de la compilation, nécessitant un nombre quelconque d'objets d'exécution, y compris zéro objet si elle détecte que le résultat n'est pas nécessaire au moment de l'exécution.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X