web-dev-qa-db-fra.com

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

On m'a demandé dans une interview sur le nombre d'objets qui seront créés sur le 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éé dans le pool de chaînes.

3 serait 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? Sinon, quelle est la bonne réponse?

36
bhpsh

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

Java 8

Sur ma machine, avec Java 1.8.0_201, votre extrait de code entraîne ce 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 instance String produite dynamiquement par StringBuilder#toString ).

Java 12

Sur ma machine, avec Java 12.0.2, le bytecode est

// 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

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


* Creusons un peu plus profondément.

12.5. Création de nouvelles instances de classe

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

  • Le chargement d'une classe ou d'une interface qui contient un littéral de chaîne ( §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 indiquant la même séquence de points de code Unicode a déjà été internée.)

En d'autres termes, lorsque vous démarrez une application, il existe déjà des objets dans le pool de chaînes. Vous savez à peine ce qu'elles sont et d'où elles viennent (sauf si vous scannez toutes les classes chargées pour tous les littéraux qu'elles contiennent).

La classe Java.lang.String Sera sans aucun doute chargée en tant que classe JVM essentielle, 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, en choisissons quelques littéraux, mettons un point d'arrêt au tout début de notre programme et 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 bien là.

Une découverte intéressante, le filtrage de cette IDEA a un effet secondaire: les sous-chaînes que je cherchais ont également été ajoutées à la piscine. La taille du pool a augmenté d'une unité ("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 d'appeler String str1 = "First";, Nous ne pouvons donc pas affirmer avec fermeté que la ligne crée une nouvelle instance.

31
Andrew Tobilko

Avec les informations fournies, la question ne peut pas être définitivement résolue. Comme indiqué dans le JLS, §15.18.1 :

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

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

Je pense que le mieux que nous puissions faire est de donner un intervalle comme réponse:

  • un compilateur intelligent peut être en mesure de déduire que str1 à str3 ne sont jamais utilisés et replient la concaténation pendant la compilation, de sorte qu'un seul objet String- est créé (celui référencé par str4)
  • Le nombre sensible maximal de Strings créé doit être de 5: un pour str1 à str3, un pour tmp = str1 + str2 et un pour str4 = tmp + str3.

Donc ... ma réponse serait "quelque chose entre un à cinq String- objets". Quant au nombre total d'objets créés juste pour cette opération ... je ne sais pas. Cela peut également dépendre de la manière exacte, par exemple StringBuffer est implémenté.

En passant: je me demande quelle est la raison de poser de telles questions. Normalement, on n'a pas besoin de se soucier de ces détails.

18
Turing85

Java 8 créera probablement 5 objets:

  • 3 pour les 3 littéraux
  • 1 StringBuilder
  • 1 pour le String concaténé

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

8
Puce

Il devrait être de 5:

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

  • un pour str1 + str2

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

4
Laurenz Albe

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

3
Boann

4 objets de chaîne seront créés dans le pool de constantes de chaîne. 3 pour les littéraux et 1 avec concaténation.

si nous utilisons

String s1 = new String("one")

il créera deux objets, un en pool constant et un en mémoire de tas.

si on définit:

String s1 = "one";
String s2 = new String("one");

il créera deux objets, un en pool constant et un en mémoire de tas.

2
Parmar Kamlesh

L'opération de concaténation ne crée pas ces nombreux objets String. Il crée un StringBuilder puis ajoute les chaînes. Il peut donc y avoir 5 objets, 3 (variables) + 1 (sb) + 1 (chaîne concaténée).

1
javaaddict