Quelle est la différence entre
String str = new String("abc");
et
String str = "abc";
Lorsque vous utilisez un littéral de chaîne, la chaîne peut être internée , mais lorsque vous utilisez new String("...")
, vous obtenez un nouveau objet string.
Dans cet exemple, les deux littéraux de chaîne font référence au même objet:
String a = "abc";
String b = "abc";
System.out.println(a == b); // true
Ici, 2 objets différents sont créés et ils ont des références différentes:
String c = new String("abc");
String d = new String("abc");
System.out.println(c == d); // false
En général, vous devriez utiliser la notation littérale de chaîne lorsque cela est possible. Il est plus facile à lire et donne au compilateur une chance d’optimiser votre code.
Un littéral chaîne est un concept de langage Java. C'est un littéral de chaîne:
"a String literal"
Un objet String est une instance individuelle de la classe Java.lang.String
.
String s1 = "abcde";
String s2 = new String("abcde");
String s3 = "abcde";
Tous sont valables, mais ont une légère différence. s1
fera référence à un objet interné String. Cela signifie que la séquence de caractères "abcde"
sera stockée à un emplacement central et que, chaque fois que le même littéral "abcde"
sera utilisé à nouveau, la machine virtuelle Java ne créera pas de nouvel objet String mais utilisera la référence du - mis en cache Chaîne.
s2
est censé être un nouvel objet String, nous avons donc dans ce cas:
s1 == s2 // is false
s1 == s3 // is true
s1.equals(s2) // is true
La réponse longue est disponible ici , je vais donc vous donner la réponse courte.
Quand tu fais ça:
String str = "abc";
Vous appelez la méthode intern()
sur String . Cette méthode fait référence à un pool interne d'objets String
. Si la chaîne sur laquelle vous avez appelé intern()
réside déjà dans le pool, une référence à celle-ci String
est affectée à str
. Si ce n'est pas le cas, le nouveau String
est placé dans le pool et une référence à ce dernier est ensuite attribuée à str
.
Étant donné le code suivant:
String str = "abc";
String str2 = "abc";
boolean identity = str == str2;
Lorsque vous vérifiez l'identité de l'objet en effectuant ==
(vous demandez littéralement: ces deux références pointent-elles vers le même objet?), Vous obtenez true
.
Cependant, vous n'avez pas pour intern()
Strings
. Vous pouvez forcer la création sur un nouveau Object
sur le tas en procédant comme suit:
String str = new String("abc");
String str2 = new String("abc");
boolean identity = str == str2;
Dans ce cas, str
et str2
sont des références à différents Objects
, dont aucun n'a été interné , de sorte que lorsque vous testez l'identité Object
à l'aide de ==
, vous obtiendrez false
.
En termes de bonne pratique de codage: ne pas utilisez ==
pour vérifier l’égalité des chaînes, utilisez plutôt .equals()
.
Comme les cordes sont immuables, quand vous le faites:
String a = "xyz"
lors de la création de la chaîne, la machine virtuelle Java recherche dans le groupe de chaînes s'il existe déjà une valeur de chaîne "xyz"
, si 'a'
sera simplement une référence de cette chaîne et qu'aucun nouvel objet String n'est créé.
Mais si vous dites:
String a = new String("xyz")
vous forcez la JVM à créer une nouvelle référence String
, même si "xyz"
se trouve dans son pool.
Pour plus d'informations, lisez this .
"abc"
est une chaîne littérale.
En Java, ces chaînes littérales sont regroupées en interne et la même instance String de "abc"
est utilisée partout où ce littéral de chaîne est déclaré dans votre code. Donc, "abc" == "abc"
sera toujours vrai, car ils sont tous deux la même instance de String.
En utilisant la méthode String.intern()
, vous pouvez ajouter n'importe quelle chaîne de votre choix aux chaînes regroupées en interne. Elles seront conservées en mémoire jusqu'à la sortie de Java.
D'autre part, l'utilisation de new String("abc")
créera un nouvel objet chaîne en mémoire, qui est logiquement identique au littéral "abc"
. "abc" == new String("abc")
sera toujours faux, car même s'ils sont logiquement égaux, ils font référence à des instances différentes.
Enrouler un constructeur String autour d'un littéral chaîne n'a aucune valeur, il utilise simplement inutilement plus de mémoire que nécessaire.
String est une classe dans Java différente des autres langages de programmation. Donc, comme pour chaque classe, la déclaration et l'initialisation de l'objet sont
String st1 = new String();
ou
String st2 = new String("Hello");
String st3 = new String("Hello");
Ici, st1
, st2
et st3
sont des objets différents.
C'est:
st1 == st2 // false
st1 == st3 // false
st2 == st3 // false
Parce que st1
, st2
, st3
font référence à 3 objets différents et ==
vérifie l'égalité dans l'emplacement mémoire, d'où le résultat.
Mais:
st1.equals(st2) // false
st2.equals(st3) // true
Ici, la méthode .equals()
vérifie le contenu et le contenu de st1 = ""
, st2 = "hello"
et st3 = "hello"
. D'où le résultat.
Et dans le cas de la déclaration de chaîne
String st = "hello";
Ici, intern()
la méthode de String
class est appelée et vérifie si "hello"
est dans le pool interne et si ce n'est pas le cas, elle est ajoutée au pool interne et si "hello" existe dans intern pool, alors st
pointera vers la mémoire du "hello"
existant.
Donc en cas de:
String st3 = "hello";
String st4 = "hello";
Ici:
st3 == st4 // true
Parce que st3
et st4
pointant vers la même adresse mémoire.
Aussi:
st3.equals(st4); // true as usual
Dans le premier cas, deux objets sont créés.
Dans le second cas, c'est juste un.
Bien que les deux manières str
se réfère à "abc"
.
Certains démontages sont toujours intéressants ...
$ cat Test.Java
public class Test {
public static void main(String... args) {
String abc = "abc";
String def = new String("def");
}
}
$ javap -c -v Test
Compiled from "Test.Java"
public class Test extends Java.lang.Object
SourceFile: "Test.Java"
minor version: 0
major version: 50
Constant pool:
const #1 = Method #7.#16; // Java/lang/Object."<init>":()V
const #2 = String #17; // abc
const #3 = class #18; // Java/lang/String
const #4 = String #19; // def
const #5 = Method #3.#20; // Java/lang/String."<init>":(Ljava/lang/String;)V
const #6 = class #21; // Test
const #7 = class #22; // Java/lang/Object
const #8 = Asciz <init>;
...
{
public Test(); ...
public static void main(Java.lang.String[]);
Code:
Stack=3, Locals=3, Args_size=1
0: ldc #2; // Load string constant "abc"
2: astore_1 // Store top of stack onto local variable 1
3: new #3; // class Java/lang/String
6: dup // duplicate top of stack
7: ldc #4; // Load string constant "def"
9: invokespecial #5; // Invoke constructor
12: astore_2 // Store top of stack onto local variable 2
13: return
}
En plus des réponses déjà postées, voir aussi this excellent article sur javaranch.
Selon documentation de classe String ils sont équivalents.
La documentation de String(String original)
indique également que: Sauf si une copie explicite de l'original est nécessaire, l'utilisation de ce constructeur est inutile car les chaînes sont immuables.
Recherchez d'autres réponses, car il semble que la documentation de Java soit trompeuse :(
Voici quelques comparaisons:
String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");
System.out.println(s1 == s2); //true
System.out.println(s1.equals(s2)); //true
System.out.println(s1 == s3); //false
System.out.println(s1.equals(s3)); //true
s3 = s3.intern();
System.out.println(s1 == s3); //true
System.out.println(s1.equals(s3)); //true
Lorsque intern()
est appelée, la référence est modifiée.
Il existe une différence subtile entre l'objet String et le littéral de chaîne.
String s = "abc"; // creates one String object and one reference variable
Dans ce cas simple, "abc" ira dans le pool et s s'y référera.
String s = new String("abc"); // creates two objects,and one reference variable
Dans ce cas, étant donné que nous avons utilisé le mot clé new
, Java créera un nouvel objet String dans la mémoire normale (sans pool) et s s'y référera. . De plus, le littéral "abc" sera placé dans le pool.
String s = new String("FFFF")
crée 2 objets: "FFFF"
string et String
object, qui pointe sur "FFFF"
string, c'est donc comme pointeur à pointeur (référence à référence, je ne suis pas passionné avec terminologie).
On dit que vous ne devriez jamais utiliser new String("FFFF")