N'importe qui, veuillez répondre à cela. String a = "Java"; Chaîne b = "Java"; System.out.println (a == b); true // mais System.out.println ("a == b?" + a == b); // false ...
Énergie
je ne comprends pas quand j'ai ajouté un commentaire ("a == b?) => mon résultat devient FAUX. pourquoi?
Energie
@Energy Le résultat est falsedû au fait que l'ordre des opérations dicte que l'opérateur + passe en premier, concaténant "a == b?" avec a pour créer une chaîne "a == b? Java". Ensuite, l'expression est "a==b?Java" == bévaluée à faux.
Allison B
@AllisonB l'a compris, merci beaucoup!
Énergie
Réponses:
187
new String("text");
crée explicitement une nouvelle instance d'un Stringobjet distincte par référence ; String s = "text";peut réutiliser une instance du pool de constantes de chaîne si elle est disponible.
Vous voudriez très rarement utiliser le new String(anotherString)constructeur. Depuis l'API:
String(String original): Initialise un objet nouvellement crééString afin qu'il représente la même séquence de caractères que l'argument; en d'autres termes, la chaîne nouvellement créée est une copie de la chaîne d'argument. À moins qu'une copie explicite de l'original ne soit nécessaire, l'utilisation de ce constructeur n'est pas nécessaire car les chaînes sont immuables.
==sur deux types de référence est une comparaison d'identité de référence. Deux objets qui ne le equalssont pas forcément ==. Il est généralement faux d'utiliser== des types de référence; la plupart du temps equalsdoivent être utilisés à la place.
Néanmoins, si pour une raison quelconque vous devez en créer deux equalsmais pas une ==chaîne, vous pouvez utiliser le new String(anotherString)constructeur. Il faut cependant redire que c'est très particulier et que c'est rarement l'intention.
Si j'écris: String s = new String ("abc"); Et maintenant j'écris: String s = "abc"; Will String s = "abc"; créer un nouveau littéral de chaîne dans le pool de chaînes?
Kaveesh Kanwal
Pourquoi personne ne répond à la question précédente?
zeds
2
@KaveeshKanwal Non, le littéral ne sera pas dupliqué. Comme vous pouvez le voir, il y a 2 "abc"s. Un seul d'entre eux ira au pool de chaînes et l'autre s'y référera. Ensuite, il y saura le nouvel objet approprié.
Kayaman
1
@Kaveesh Kanwal - String s = new String ("abc") ne créera qu'un nouvel objet String avec la valeur "abc". Et la 2ème instruction vérifiera si un littéral de chaîne "abc" est déjà présent ou non dans String Pool. S'il est déjà présent, la référence à l'existant est renvoyée et sinon, un nouveau littéral ("abc") est créé dans le pool de chaînes. J'espère que cela résoudra votre question !!
user968813
Il n'y a pas de «peut» à ce sujet. Le compilateur doit regrouper les littéraux de chaîne. JLS 3.10.5 .
Marquis de Lorne
119
Les littéraux de chaîne iront dans le pool de chaînes constantes .
L'instantané ci-dessous peut vous aider à le comprendre visuellement pour vous en souvenir plus longtemps.
Création d'objet ligne par ligne:
String str1 =newString("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 un nouvel opérateur, un nouvel objet chaîne est créé dans le tas avec "java5" comme valeur.
String str2 ="java5"
La référence "str2" pointe vers une valeur déjà stockée dans le pool de constantes de chaîne
String str3 =newString(str2);
Un nouvel objet chaîne est créé dans le tas avec la même valeur que référence par "str2"
String str4 ="java5";
La référence "str4" pointe vers une valeur déjà stockée dans le pool de constantes de chaîne
Bonne réponse .. mais je voulais savoir que maintenant je suis en train de changer la valeur de str1 = "java6" alors cela changera la valeur de str4?
CoronaPintu
2
oui j'ai vérifié qu'il ne changera pas la valeur de str4
CoronaPintu
@Braj Pouvez-vous fournir la documentation de l'affirmation de votre réponse?
Basil Bourque
@Braj: les en-têtes du «tas» et du «pool» du tableau sont-ils censés être inversés?
Rahul Kurup du
Pas correcte. Le pool constant est créé au moment de la compilation et non au moment de l'exécution. N'utilisez pas la mise en forme des guillemets pour le texte qui n'est pas cité.
l'autre crée une chaîne dans le pool constant ( "text") et une autre chaîne dans l'espace de tas normal ( s). Les deux chaînes auront la même valeur, celle de "texte".
String s =newString("text");
s est alors perdu (éligible au GC) s'il n'est pas utilisé par la suite.
Les littéraux de chaîne en revanche sont réutilisés. Si vous utilisez "text"à plusieurs endroits de votre classe, ce sera en fait une et une seule chaîne (c'est-à-dire plusieurs références à la même chaîne dans le pool).
De plus, un littéral de chaîne fait toujours référence à la même instance de la classe String. En effet, les littéraux de chaîne - ou, plus généralement, les chaînes qui sont les valeurs d'expressions constantes (§15.28) - sont "internés" de manière à partager des instances uniques, en utilisant la méthode String.intern.
Exemple 3.10.5-1. Littéraux de chaîne
Le programme composé de l'unité de compilation (§7.3):
Un littéral de chaîne est une référence à une instance de la classe 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 de points de code Unicode constituant le littéral de chaîne.
Le langage de programmation Java requiert que des littéraux de chaîne identiques (c'est-à-dire des littéraux qui contiennent la même séquence de points de code) doivent faire référence à la même instance de classe String (JLS §3.10.5). En outre, si la méthode String.intern est appelée sur une 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 comme un littéral. Ainsi, l'expression suivante 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 méthode String.intern a déjà été appelée sur une instance de classe String contenant une séquence de points de code Unicode identique à celle donnée par la structure CONSTANT_String_info, le résultat de la dérivation littérale de chaîne est une référence à cette même instance de classe String.
Sinon, une nouvelle instance de la classe String est créée contenant la séquence de points de code Unicode donnée par la structure CONSTANT_String_info; une référence à cette instance de classe est le résultat d'une dérivation littérale de chaîne. Enfin, la méthode interne de la nouvelle instance de String est invoquée.
Bytecode
Il est également instructif de regarder l'implémentation du bytecode sur OpenJDK 7.
Si nous décompilons:
publicclassStringPool{publicstaticvoid main(String[] args){String a ="abc";String b ="abc";String c =newString("abc");System.out.println(a);System.out.println(b);System.out.println(a == c);}}
str1n'est pas impliqué dans la valeur de str2ou str3ou str4en aucune façon.
Marquis de Lorne
1
Pensez à "bla"être une usine magique commeStrings.createString("bla") (pseudo). L'usine détient un pool de toutes les chaînes encore créé de cette façon.
S'il est invoqué, il vérifie s'il existe déjà une chaîne dans le pool avec cette valeur. S'il est vrai, il renvoie cet objet chaîne, donc les chaînes obtenues de cette façon sont en effet le même objet.
Sinon, il crée un nouvel objet chaîne 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 new String("")remplace ce comportement en contournant le pool de littéraux de chaîne. Donc, l'égalité doit 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 d'objet.
La «fabrique magique» à laquelle vous faites référence n'est ni plus ni moins que le compilateur Java. C'est une erreur d'écrire ce processus comme s'il s'était produit au moment de l'exécution.
Marquis de Lorne
1
Voici une façon simple de comprendre la différence: -
String s ="abc";String s1="abc";String s2=newString("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, la nouvelle chaîne () créera toujours une nouvelle instance.
Tout littéral de chaîne est créé dans le pool de littéraux de chaîne et le pool n'autorise aucun doublon. Ainsi, si deux ou plusieurs objets chaîne sont initialisés avec la même valeur littérale, tous les objets pointeront vers le même littéral.
String obj1 ="abc";String obj2 ="abc";
"obj1" et "obj2" pointeront vers le même littéral de chaîne et le pool de littéraux de chaîne n'aura qu'un seul littéral "abc".
Lorsque nous créons un objet de classe String à l'aide du nouveau mot clé, la chaîne ainsi créée est stockée dans la mémoire de tas. Tout littéral de chaîne passé en paramètre au constructeur de la classe String est cependant stocké dans le pool de chaînes. Si nous créons plusieurs objets en utilisant la même valeur avec le nouvel opérateur, un nouvel objet sera créé à chaque fois dans le tas, car ce nouvel opérateur doit être évité.
"obj1" et "obj2" pointeront vers deux objets différents dans le tas et le pool de littéraux de chaîne n'aura qu'un seul littéral "abc".
Il convient également de noter en ce qui concerne le comportement des chaînes que toute nouvelle affectation ou concaténation effectuée sur une chaîne crée un nouvel objet en mémoire.
Maintenant dans le cas ci-dessus:
Ligne 1: le littéral "abc" est stocké dans le pool de chaînes.
Ligne 2: le littéral "abcdef" est stocké dans le pool de chaînes.
Ligne 3: Un nouveau littéral "xyz" est stocké dans le pool de chaînes et "str1" commence à pointer vers ce littéral.
Ligne 4: Puisque la valeur est générée en ajoutant à une autre variable, le résultat est stocké dans la mémoire du tas et le littéral ajouté "ghi" sera vérifié pour son existence dans le pool de chaînes et sera créé car il n'existe pas dans le cas ci-dessus.
Bien qu'il ait la même apparence du point de vue des programmeurs, il a un impact important sur les performances. Vous voudriez utiliser presque toujours le premier formulaire.
Il vérifiera si le pool de constantes String contient déjà String "bonjour"? S'il est présent, il n'ajoutera pas d'entrée dans le pool constant de chaînes. S'il n'est pas présent, il ajoutera une entrée dans le pool constant de chaînes.
Un objet sera créé dans une zone de mémoire de tas et str référence à un objet créé dans un emplacement de mémoire de tas.
si vous voulez une strréférence à un objet point contenant dans le pool de constantes String, alors il faut appeler explicitementstr.intern();
String str ="world";
Il vérifiera si le pool de constantes String contient déjà String "bonjour"? S'il est présent, il n'ajoutera pas d'entrée dans le pool constant de chaînes. S'il n'est pas présent, il ajoutera une entrée dans le pool constant de chaînes.
Dans les deux cas ci-dessus, la strréférence pointe vers la chaîne "world"présente dans le pool constant.
'It' étant le compilateur Java. Le littéral de chaîne crée une entrée unique dans le pool constant, au moment de la compilation. C'est une erreur de désactiver ce processus comme s'il se produisait à l'exécution.
Marquis de Lorne
Pouvez-vous expliquer clairement ce qui ne va pas dans ce message?
Jayesh
Ce qui ne va pas dans ce post, c'est que le littéral de chaîne est mis en commun au moment du complle, comme je l'ai déjà dit. Pas lors de l'exécution du code, comme dans votre réponse.
Marquis de Lorne
@EJP J'apprécie votre réponse. Pouvez-vous indiquer la ligne exacte qui ne répond pas correctement? Je vois que toutes les réponses ci-dessus sont les mêmes que celles que j'ai écrites. Aidez-moi, je veux corriger ma compréhension. Merci.
Jayesh
Vous avez écrit sur l'ensemble du processus comme si tout se déroulait lors de l'exécution de la ligne de code, ce qui, comme je vous l'ai dit à plusieurs reprises, n'est pas le cas. Vous ne pouvez pas réduire tout cela à une seule «ligne exacte» en vous trompant dans votre réponse.
Marquis de Lorne
0
Lorsque vous stockez une chaîne sous
String string1 ="Hello";
directement, la JVM crée un objet String avec le prix indiqué pendant un bloc de mémoire distinct appelé pool de constantes String.
Et chaque fois que nous avons tendance à essayer de produire une autre chaîne comme
String string2 ="Hello";
La JVM vérifie s'il existe ou non un objet String à prix constant dans le pool de constantes String, si tel est le cas, plutôt que de créer un nouvel objet JVM attribue la référence de l'objet existant à la nouvelle variable.
Et quand nous stockons String sous
String string =newString("Hello");
en utilisant le nouveau mot-clé, un tout nouvel objet avec le prix donné est créé quel que soit le contenu du pool de constantes String.
false
dû au fait que l'ordre des opérations dicte que l'opérateur + passe en premier, concaténant "a == b?" avec a pour créer une chaîne "a == b? Java". Ensuite, l'expression est"a==b?Java" == b
évaluée à faux.Réponses:
new String("text");
crée explicitement une nouvelle instance d'unString
objet distincte par référence ;String s = "text";
peut réutiliser une instance du pool de constantes de chaîne si elle est disponible.Vous voudriez très rarement utiliser le
new String(anotherString)
constructeur. Depuis l'API:Questions connexes
Que signifie la distinction référentielle
Examinez l'extrait de code suivant:
==
sur deux types de référence est une comparaison d'identité de référence. Deux objets qui ne leequals
sont pas forcément==
. Il est généralement faux d'utiliser==
des types de référence; la plupart du tempsequals
doivent être utilisés à la place.Néanmoins, si pour une raison quelconque vous devez en créer deux
equals
mais pas une==
chaîne, vous pouvez utiliser lenew String(anotherString)
constructeur. Il faut cependant redire que c'est très particulier et que c'est rarement l'intention.Références
class Object
-boolean Object(equals)
Problèmes liés
la source
"abc"
s. Un seul d'entre eux ira au pool de chaînes et l'autre s'y référera. Ensuite, il ys
aura le nouvel objet approprié.Les littéraux de chaîne iront dans le pool de chaînes constantes .
L'instantané ci-dessous peut vous aider à le comprendre visuellement pour vous en souvenir plus longtemps.
Création d'objet ligne par ligne:
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 un nouvel opérateur, un nouvel objet chaîne est créé dans le tas avec "java5" comme valeur.
La référence "str2" pointe vers une valeur déjà stockée dans le pool de constantes de chaîne
Un nouvel objet chaîne est créé dans le tas avec la même valeur que référence par "str2"
La référence "str4" pointe vers une valeur déjà stockée dans le pool de constantes de chaîne
Total des objets: tas - 2, piscine - 1
Pour en savoir plus sur la communauté Oracle
la source
On crée une chaîne dans le pool de constantes de chaîne
l'autre crée une chaîne dans le pool constant (
"text"
) et une autre chaîne dans l'espace de tas normal (s
). Les deux chaînes auront la même valeur, celle de "texte".s
est alors perdu (éligible au GC) s'il n'est pas utilisé par la suite.Les littéraux de chaîne en revanche sont réutilisés. Si vous utilisez
"text"
à plusieurs endroits de votre classe, ce sera en fait une et une seule chaîne (c'est-à-dire plusieurs références à la même chaîne dans le pool).la source
JLS
Le concept est appelé "interning" par le JLS.
Passage pertinent de JLS 7 3.10.5 :
JVMS
JVMS 7 5.1 dit :
Bytecode
Il est également instructif de regarder l'implémentation du bytecode sur OpenJDK 7.
Si nous décompilons:
nous avons sur le bassin constant:
et
main
:Notez comment:
0
et3
: la mêmeldc #2
constante est chargée (les littéraux)12
: une nouvelle instance de chaîne est créée (avec#2
comme argument)35
:a
etc
sont comparés comme des objets normaux avecif_acmpne
La représentation des chaînes constantes est assez magique sur le bytecode:
new String
)et la citation JVMS ci-dessus semble dire que chaque fois que l'Utf8 pointé est le même, 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 la table des constantes via l' attribut ConstantValueldc
Conclusion : le pool de chaînes prend directement en charge le bytecode et la représentation en mémoire est efficace.
Bonus: comparez cela au pool Integer , qui n'a pas de prise en charge directe du bytecode (c'est-à-dire pas d'
CONSTANT_String_info
analogue).la source
@ Braj: je pense que vous avez mentionné l'inverse. S'il vous plait corrigez moi si je me trompe
Création d'objet ligne par ligne:
String str1 = new String ("java5")
Chaîne str2 = "java5"
Chaîne str3 = nouvelle chaîne (str2)
Chaîne str4 = "java5"
la source
str1
n'est pas impliqué dans la valeur destr2
oustr3
oustr4
en aucune façon.Pensez à
"bla"
être une usine magique commeStrings.createString("bla")
(pseudo). L'usine détient un pool de toutes les chaînes encore créé de cette façon.S'il est invoqué, il vérifie s'il existe déjà une chaîne dans le pool avec cette valeur. S'il est vrai, il renvoie cet objet chaîne, donc les chaînes obtenues de cette façon sont en effet le même objet.
Sinon, il crée un nouvel objet chaîne 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
new String("")
remplace ce comportement en contournant le pool de littéraux de chaîne. Donc, l'égalité doit toujours être vérifiée en utilisantequals()
qui compare la séquence de caractères au lieu de l'égalité de référence d'objet.la source
Voici une façon simple de comprendre la différence: -
la sortie est
Ainsi, la nouvelle chaîne () créera toujours une nouvelle instance.
la source
Tout littéral de chaîne est créé dans le pool de littéraux de chaîne et le pool n'autorise aucun doublon. Ainsi, si deux ou plusieurs objets chaîne sont initialisés avec la même valeur littérale, tous les objets pointeront vers le même littéral.
"obj1" et "obj2" pointeront vers le même littéral de chaîne et le pool de littéraux de chaîne n'aura qu'un seul littéral "abc".
Lorsque nous créons un objet de classe String à l'aide du nouveau mot clé, la chaîne ainsi créée est stockée dans la mémoire de tas. Tout littéral de chaîne passé en paramètre au constructeur de la classe String est cependant stocké dans le pool de chaînes. Si nous créons plusieurs objets en utilisant la même valeur avec le nouvel opérateur, un nouvel objet sera créé à chaque fois dans le tas, car ce nouvel opérateur doit être évité.
"obj1" et "obj2" pointeront vers deux objets différents dans le tas et le pool de littéraux de chaîne n'aura qu'un seul littéral "abc".
Il convient également de noter en ce qui concerne le comportement des chaînes que toute nouvelle affectation ou concaténation effectuée sur une chaîne crée un nouvel objet en mémoire.
Maintenant dans le cas ci-dessus:
Ligne 1: le littéral "abc" est stocké dans le pool de chaînes.
Ligne 2: le littéral "abcdef" est stocké dans le pool de chaînes.
Ligne 3: Un nouveau littéral "xyz" est stocké dans le pool de chaînes et "str1" commence à pointer vers ce littéral.
Ligne 4: Puisque la valeur est générée en ajoutant à une autre variable, le résultat est stocké dans la mémoire du tas et le littéral ajouté "ghi" sera vérifié pour son existence dans le pool de chaînes et sera créé car il n'existe pas dans le cas ci-dessus.
la source
Bien qu'il ait la même apparence du point de vue des programmeurs, il a un impact important sur les performances. Vous voudriez utiliser presque toujours le premier formulaire.
la source
Il vérifiera si le pool de constantes String contient déjà String "bonjour"? S'il est présent, il n'ajoutera pas d'entrée dans le pool constant de chaînes. S'il n'est pas présent, il ajoutera une entrée dans le pool constant de chaînes.
Un objet sera créé dans une zone de mémoire de tas et
str
référence à un objet créé dans un emplacement de mémoire de tas.si vous voulez une
str
référence à un objet point contenant dans le pool de constantes String, alors il faut appeler explicitementstr.intern();
Il vérifiera si le pool de constantes String contient déjà String "bonjour"? S'il est présent, il n'ajoutera pas d'entrée dans le pool constant de chaînes. S'il n'est pas présent, il ajoutera une entrée dans le pool constant de chaînes.
Dans les deux cas ci-dessus, la
str
référence pointe vers la chaîne"world"
présente dans le pool constant.la source
Lorsque vous stockez une chaîne sous
directement, la JVM crée un objet String avec le prix indiqué pendant un bloc de mémoire distinct appelé pool de constantes String.
Et chaque fois que nous avons tendance à essayer de produire une autre chaîne comme
La JVM vérifie s'il existe ou non un objet String à prix constant dans le pool de constantes String, si tel est le cas, plutôt que de créer un nouvel objet JVM attribue la référence de l'objet existant à la nouvelle variable.
Et quand nous stockons String sous
en utilisant le nouveau mot-clé, un tout nouvel objet avec le prix donné est créé quel que soit le contenu du pool de constantes String.
la source