Quelle est la différence entre" texte"et nouvelle chaîne ("texte")?


Quelle est la différence entre ces deux énoncés suivants?

String s = "text";

String s = new String("text");
Author: nbro, 2010-06-16

9 answers

new String("text"); crée explicitement une nouvelle instance référentiellement distincte d'un objet String; String s = "text";peut réutiliser une instance du string constant pool si une instance est disponible.

Vous très rarement voudrait jamais utiliser le new String(anotherString) constructeur. De l'API:

String(String original) : Initialise une nouvellement créé String objet de sorte qu'il représente la même séquence de caractères comme argument; en d'autres termes, la chaîne nouvellement créée est un copie de la chaîne d'argument. Sauf si une copie explicite de l'original est nécessaire, l'utilisation de ce constructeur est inutile car les chaînes sont immuables.

Questions connexes


Que signifie la distinction référentielle

Examinez l'extrait de code suivant:

    String s1 = "foobar";
    String s2 = "foobar";

    System.out.println(s1 == s2);      // true

    s2 = new String("foobar");
    System.out.println(s1 == s2);      // false
    System.out.println(s1.equals(s2)); // true

== sur deux types de référence est une comparaison d'identité de référence. Deux objets qui sont equals ne sont pas nécessairement ==. Il est généralement erroné d'utiliser == sur les types de référence; la plupart du temps, equals doit être utilisé à la place.

Néanmoins, si pour une raison quelconque vous devez créer deux equals mais pas == string, vous pouvez utiliser le constructeur new String(anotherString). Il faut cependant redire que c'est très particulier, et c'est rarement intention.

Références

Questions connexes

 154
Author: polygenelubricants, 2017-05-23 11:54:44

String littéraux ira dans String Constant Pool.

L'instantané ci-dessous peut vous aider à le comprendre visuellement pour vous en souvenir plus longtemps.

entrez la description de l'image ici


Création d'objet ligne par ligne:

String str1 = new String("java5");

En utilisant le littéral de chaîne "java5" dans le constructeur, une nouvelle valeur de chaîne est stockée dans le pool de constantes de chaîne. En utilisant new operator, un nouvel objet string est créé dans le tas avec "java5" comme valeur.

String str2 = "java5"

Référence "str2" est pointé vers la valeur déjà stockée dans le pool de constantes de chaîne

String str3 = new String(str2);

Un nouvel objet string est créé dans le tas avec la même valeur comme référence par "str2"

String str4 = "java5";

La référence "str4" est pointée vers la valeur déjà stockée dans le pool de constantes de chaîne

Total des objets: Tas-2, Pool - 1

Pour en savoir plus sur la communauté Oracle

 98
Author: Braj, 2018-01-14 14:02:00

On crée une chaîne dans le pool de constantes de chaîne

String s = "text";

L'autre crée une chaîne dans le pool de constantes ("text") et une autre chaîne dans l'espace de tas normal (s). Les deux chaînes ont la même valeur, celle de "texte".

String s = new String("text");

s est alors perdu (éligible au GC) s'il est inutilisé ultérieurement.

Les littéraux de chaîne d'autre part sont réutilisés. Si vous utilisez {[2] } à plusieurs endroits de votre classe, ce sera en fait une et une seule chaîne (c'est-à-dire plusieurs références de la même chaîne dans la piscine).

 15
Author: , 2010-06-16 11:57:27

JLS

Le concept est appelé "internement" par le JLS.

Passage pertinent de JLS 7 3.10.5:

De plus, un littéral de chaîne fait toujours référence à la même instance de class String. En effet, les littéraux de chaîne-ou, plus généralement, les chaînes qui sont les valeurs des expressions constantes (§15.28) - sont "internés" de manière à partager des instances uniques, en utilisant la méthode String.stagiaire.

Exemple 3.10.5-1. Chaîne Littéraux

Le programme constitué par l'unité de compilation (§7.3):

package testPackage;
class Test {
    public static void main(String[] args) {
        String hello = "Hello", lo = "lo";
        System.out.print((hello == "Hello") + " ");
        System.out.print((Other.hello == hello) + " ");
        System.out.print((other.Other.hello == hello) + " ");
        System.out.print((hello == ("Hel"+"lo")) + " ");
        System.out.print((hello == ("Hel"+lo)) + " ");
        System.out.println(hello == ("Hel"+lo).intern());
    }
}
class Other { static String hello = "Hello"; }

Et l'unité de compilation:

package other;
public class Other { public static String hello = "Hello"; }

Produit la sortie:

true true true true false true

JVM

JVM 7 5.1, dit - :

Un littéral de chaîne est une référence à une instance de class String, et est dérivé d'une structure CONSTANT_String_info (§4.4.3) dans la représentation binaire d'une classe ou d'une interface. La structure CONSTANT_String_info donne la séquence des points de code Unicode constituant le littéral de chaîne.

Le langage de programmation Java exige que les littéraux de chaîne identiques (c'est-à-dire les littéraux contenant la même séquence de points de code) se réfèrent à la même instance de chaîne de classe (JLS §3.10.5). En outre, si la chaîne de méthode.intern est appelé sur n'importe quelle chaîne, le résultat est une référence à la même instance de classe qui serait renvoyée si cette chaîne apparaissait en tant que littéral. Ainsi, les éléments suivants l'expression doit avoir la valeur true:

("a" + "b" + "c").intern() == "abc"

Pour dériver un littéral de chaîne, la machine virtuelle Java examine la séquence de points de code donnée par la structure CONSTANT_String_info.

  • Si la chaîne de méthode.intern a déjà été appelé sur une instance de chaîne de classe contenant une séquence de points de code Unicode identique à celle donnée par la structure CONSTANT_String_info, alors le résultat de la dérivation littérale de chaîne est une référence à cette même instance de chaîne de classe.

  • Sinon, une nouvelle instance de chaîne de classe est créée contenant la séquence de points de code Unicode donnés par la structure CONSTANT_String_info; une référence à cette instance de classe est le résultat de la dérivation littérale de chaîne. Enfin, la méthode intern de la nouvelle instance de chaîne est appelée.

Bytecode

Il est également instructif de regarder l'implémentation du bytecode sur OpenJDK 7.

Si nous décompiler:

public class StringPool {
    public static void main(String[] args) {
        String a = "abc";
        String b = "abc";
        String c = new String("abc");
        System.out.println(a);
        System.out.println(b);
        System.out.println(a == c);
    }
}

Nous avons sur le pool constant:

#2 = String             #32   // abc
[...]
#32 = Utf8               abc

Et main:

 0: ldc           #2          // String abc
 2: astore_1
 3: ldc           #2          // String abc
 5: astore_2
 6: new           #3          // class java/lang/String
 9: dup
10: ldc           #2          // String abc
12: invokespecial #4          // Method java/lang/String."<init>":(Ljava/lang/String;)V
15: astore_3
16: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
19: aload_1
20: invokevirtual #6          // Method java/io/PrintStream.println:(Ljava/lang/String;)V
23: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
26: aload_2
27: invokevirtual #6          // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: getstatic     #5          // Field java/lang/System.out:Ljava/io/PrintStream;
33: aload_1
34: aload_3
35: if_acmpne     42
38: iconst_1
39: goto          43
42: iconst_0
43: invokevirtual #7          // Method java/io/PrintStream.println:(Z)V

Notez comment:

  • 0 et 3: la même constante ldc #2 est chargée (les littéraux)
  • 12: une nouvelle instance de chaîne est créé (avec #2 comme argument)
  • 35: a et {[15] } sont comparés en tant qu'objets réguliers avec if_acmpne

La représentation des chaînes constantes est assez magique sur le bytecode:

  • il a un la structure dédiée CONSTANT_String_info, contrairement aux objets réguliers (par exemple new String)
  • la structure pointe vers une structure CONSTANT_Utf8_info qui contient les données. C'est les seules données nécessaires pour représenter la chaîne.

Et la citation JVM ci-dessus semble dire que chaque fois que l'Utf8 pointé est le même, alors des instances identiques sont chargées par ldc.

J'ai fait des tests similaires pour les champs, et:

  • static final String s = "abc" pointe vers le table constante à travers l'attribut ConstantValue
  • les champs non finaux n'ont pas cet attribut, mais peuvent toujours être initialisés avec ldc

Conclusion: il existe un support direct du bytecode pour le pool de chaînes, et la représentation de la mémoire est efficace.

Bonus: comparez cela au Pool entier , qui n'a pas de support direct de bytecode (c'est-à-dire pas d'analogue CONSTANT_String_info).

Pensez à "bla" être une usine magique comme Strings.createString("bla") (pseudo). L'usine détient un pool de toutes les chaînes encore créées de cette façon.

S'il est invoqué, il vérifie s'il y a déjà une chaîne dans le pool avec cette valeur. Si true, il renvoie cet objet string, donc les chaînes obtenues de cette façon sont en effet le même objet.

Sinon, il crée un nouvel objet string en interne, l'enregistre dans le pool puis le renvoie. Ainsi, lorsque la même valeur de chaîne est interrogée la prochaine fois, elle renvoie la même instance.

La création manuelle de new String("") remplace ce comportement en contournant le pool littéral de chaîne. L'égalité doit donc toujours être vérifiée en utilisant equals() qui compare la séquence de caractères au lieu de l'égalité de référence de l'objet.

 1
Author: b_erb, 2010-06-16 10:46:07

Une façon simple de comprendre la différence est ci-dessous: -

String s ="abc";
String s1= "abc";
String s2=new String("abc");

        if(s==s1){
            System.out.println("s==s1 is true");
        }else{
            System.out.println("s==s1 is false");
        }
        if(s==s2){
            System.out.println("s==s2 is true");
        }else{
            System.out.println("s==s2 is false");
        }

La sortie est

s==s1 is true
s==s2 is false

Ainsi, new String() créera toujours une nouvelle instance.

 1
Author: Shashank T, 2010-06-16 11:19:49

@Braj : je pense que vous avez mentionné l'inverse. Veuillez me corriger si je me trompe

Création d'objet ligne par ligne:

Chaîne str1 = nouvelle chaîne("java5")

   Pool- "java5" (1 Object)

   Heap - str1 => "java5" (1 Object)

Chaîne str2 = "java5"

  pool- str2 => "java5" (1 Object)

  heap - str1 => "java5" (1 Object)

Chaîne str3 = nouvelle chaîne (str2)

  pool- str2 => "java5" (1 Object)

  heap- str1 => "java5", str3 => "java5" (2 Objects)

Chaîne str4 = "java5"

  pool - str2 => str4 => "java5" (1 Object)

  heap - str1 => "java5", str3 => "java5" (2 Objects)
 1
Author: SDC, 2015-07-07 02:32:00

Bien qu'il se ressemble du point de vue des programmeurs, il a un grand impact sur les performances. Vous voudriez utiliser le premier formulaire presque toujours.

 0
Author: fastcodejava, 2010-06-17 04:38:32
String str = new String("hello")

Il vérifiera si le pool de constantes de chaîne contient déjà la chaîne "hello"? S'il est présent, il n'ajoutera pas d'entrée dans le pool de constantes de chaîne. S'il n'est pas présent, il ajoutera une entrée dans le pool de constantes de chaîne.

Un objet sera créé dans une zone de mémoire de tas et str points de référence à l'objet créé dans l'emplacement de mémoire de tas.

Si vous voulez str référence à un objet point contenant dans un pool de constantes de chaîne, il faut appeler explicitement str.intern();

String str = "world";

Il vérifiera si le pool de constantes de chaîne contient déjà la chaîne "hello"? S'il est présent, il n'ajoutera pas d'entrée dans le pool de constantes de chaîne. S'il n'est pas présent, il ajoutera une entrée dans le pool de constantes de chaîne.

Dans les deux cas ci-dessus, str référence à la chaîne "world" présente dans le pool constant.

 0
Author: Jayesh, 2015-09-15 10:24:09