web-dev-qa-db-fra.com

Questions sur le pool de chaînes Java

Considérez ce code:

String first = "abc"; 
String second = new String("abc");

Lorsque vous utilisez le mot clé new, Java créera à nouveau le abcString à droite? Cela sera-t-il stocké sur le tas normal ou sur le String pool? Combien de Strings se termineront dans le String pool?

67
andandandand

Si vous utilisez le mot clé new, un nouvel objet String sera créé. Notez que les objets sont toujours sur le tas - le pool de chaînes n'est pas une zone de mémoire séparée qui est distincte du tas.

Le pool de chaînes est comme un cache. Si tu fais ça:

String s = "abc";
String p = "abc";

alors le compilateur Java est suffisamment intelligent pour créer un seul objet String, et s et p feront tous deux référence à la même chaîne Si vous procédez ainsi:

String s = new String("abc");

alors il y aura un objet String dans le pool, celui qui représente le littéral "abc", et il y aura un objet String séparé, pas dans le pool, qui contient une copie du contenu de l'objet regroupé. Puisque String est immuable en Java, vous ne gagnez rien en faisant cela; appeler new String("literal") n'a jamais de sens dans Java et est inutilement inefficace.

Notez que vous pouvez appeler intern() sur un objet String. Cela placera l'objet String dans le pool s'il n'est pas déjà là et renverra la référence à la chaîne regroupée. (S'il était déjà dans le pool, il renvoie simplement une référence à l'objet qui était déjà là). Voir la documentation de l'API pour cette méthode pour plus d'informations.

Voir aussi String interning (Wikipedia).

95
Jesper

Dans bytecode , la première affectation est:

 Code: 
 0: ldc # 2; // Chaîne abc 
 2: astore_1 

alors que le second est:

 3: nouveau n ° 3; // classe Java/lang/String 
 6: dup 
 7: ldc # 2; // Chaîne abc 
 9: invokespecial # 4; // Méthode Java/lang/String. "" :( Ljava/lang/String;) V 

Ainsi, le premier est dans le pool (à la position # 2) tandis que le second sera stocké dans le tas.

[~ # ~] modifier [~ # ~]

Depuis le CONSTANT_String_infostocker l'index sous U2 (16 bits, non signé) le pool peut contenir au maximum 2**16 = 65535 références. Dans le cas où vous vous souciez ici plus de limites de la JVM .

12
dfa

Chaque fois que votre code crée un littéral de chaîne

par exemple:

String str="Hello"; (string literal) 

la JVM vérifie d'abord le pool de littéraux de chaîne. Si la chaîne existe déjà dans le pool, une référence à l'instance regroupée est renvoyée. Si la chaîne n'existe pas dans le pool, un nouvel objet String instancie, puis est placé dans le pool. Java peut faire cette optimisation car les chaînes sont immuables et peuvent être partagées sans crainte de corruption de données

7
loudiyimo
String strObject = new String("Java");

et

String strLiteral = "Java";

Les deux expressions vous donnent un objet String, mais il y a une différence subtile entre elles. Lorsque vous créez un objet String à l'aide de l'opérateur new (), il crée toujours un nouvel objet dans la mémoire de segment de mémoire. D'un autre côté, si vous créez un objet en utilisant la syntaxe littérale String, par exemple "Java", il peut renvoyer un objet existant du pool de chaînes (un cache d'objet de chaîne dans l'espace Perm gen, qui est maintenant déplacé vers l'espace de mémoire dans la récente Java), s'il existe déjà .

3
vimalraj

La seule fois où vous devez utiliser une nouvelle chaîne (foo) est lorsque vous voulez casser ==, ce qui est un cas étrange, ou lorsque foo est une sous-chaîne d'une chaîne beaucoup plus grande qui a une durée de vie limitée, comme

String mystring;
{
   String source = getSomeHeinouslyLargeString();
   mystring = new String(source.substring(1,3));
}
2
MeBigFatGuy
String first = "abc"; 
String second = new String("abc");

Dans le premier cas, un seul objet sera créé dans Pool. Dans le deuxième cas, deux objets en créeront un dans le pool (s'il n'existe pas auparavant dans le pool) et un dans le tas.

Lorsque vous passez une valeur avec des guillemets doubles ex: "abc", vous créez un objet dans le pool et le passez au constructeur de chaîne pour créer un nouvel objet avec la même valeur dans le tas.

Si vous avez vu le constructeur de chaîne, vous pouvez voir qu'il accepte une chaîne. Quelle est cette chaîne? Avant la création, quel est cet objet chaîne. Ce n'est rien d'autre qu'un objet stocké dans le pool de constantes de chaîne.

0
Kprasanta

Bien que tard, cela peut être utile pour quelqu'un qui rencontre encore ceci:

String first = "abc";
//One instance object in pool created. Instance variable “first” refers/points to pooled object

String second = new String("abc");    
//One instance object in heap created. Object in pool creation step will be skipped on account of first statement.

Donc, au total, 2 objets d'instance seront créés. Un dans la piscine et l'autre dans le tas

Explication détaillée

Chaîne en premier = "abc";

Voici un objet chaîne avec le contenu "abc" créé dans le pool. La variable d'instance "first" pointera vers un pool d'objets avec le contenu "abc".

String second = new String ("abc");

Ici, un autre objet chaîne avec le contenu "abc" sera créé en tas. La variable d'instance "second" pointera vers un tas avec le contenu "abc". Un objet chaîne avec le contenu "abc" créé dans le pool sera ignoré en raison de la première instruction. Raison ci-dessous.

Raisons

Si la déclaration antérieure supposée (String first = "abc";) n'est pas là avec le même contenu, alors généralement avec le mot-clé "new", 2 objets de chaîne seront créés l'un en tas (en dehors du pool) et l'autre en pool (une zone de sous-ensemble de tas). De plus, la variable d'instance "second" doit pointer vers un tas uniquement, indépendamment du fait que les objets soient dans le pool ou non.

Maintenant, en raison de la présence d'une instruction précédente (String first = "abc";) avec le même contenu que dans la nouvelle String ("abc"), un seul objet (avec le contenu "abc") est conservé dans le pool. Donc à cause de la 1ère instruction, la deuxième instruction n'aura qu'un seul objet créé au lieu de 2 et cet objet est en tas. La création d'objet de pool sera ignorée.

//Additional Test on the concept
System.out.println(first==second);  //returns false. Because first points to pool object while second points to heap object. And both objects are different (on account of different memory locations).

second = second.intern();           //After interning, second now points to pool object. Note: intern is used so that reference variable points to pool area object and not heap object. Clearly it is applicable when we use new keyword.

System.out.println(first==second);  //returns true. Because now both first and second objects now points to same pool object.
0
vinsinraw