Il existe deux formes de création d'objets chaîne en Java, l'une est une forme littérale, telle que String str = "droid";, et l'autre consiste à utiliser new, une méthode standard de construction d'objets, telle que String str = new String( " droïde");, ces deux méthodes sont souvent utilisées lors de l'écriture de code, notamment la méthode littérale. Cependant, il existe en réalité certaines différences en termes de performances et d’utilisation de la mémoire entre ces deux implémentations. Tout cela est dû au fait que afin de réduire la création répétée d'objets chaîne, la JVM maintient une mémoire spéciale. Cette mémoire est appelée pool de constantes de chaîne ou pool de littéraux de chaîne.
Principe de fonctionnement
Lorsqu'un objet chaîne est créé sous la forme d'un littéral dans le code, la JVM vérifiera d'abord le littéral. S'il existe une référence à un objet chaîne avec le même contenu dans le pool de constantes de chaîne, la référence sera renvoyée, sinon. une nouvelle chaîne sera créée. L'objet est créé, cette référence est placée dans le pool de constantes de chaîne et la référence est renvoyée.
Donnez un exemple
Forme de création littérale
Copiez le code comme suit :
Chaîne str1 = "droïde" ;
La JVM détecte ce littéral. Ici, nous pensons qu'il n'y a aucun objet dont le contenu est droïde. La JVM ne peut pas trouver l'existence d'un objet chaîne avec le contenu de droid via le pool de constantes de chaîne, elle créera alors l'objet chaîne, puis placera la référence de l'objet nouvellement créé dans le pool de constantes de chaîne et renverra la référence au variable str1 .
S'il y a un morceau de code comme celui-ci ensuite
Copiez le code comme suit :
Chaîne str2 = "droïde" ;
De même, la JVM doit toujours détecter ce littéral. La JVM recherche le pool de constantes de chaîne et constate que l'objet chaîne avec le contenu de "droid" existe, elle renvoie donc la référence de l'objet chaîne existant à la variable str2. Notez qu'un nouvel objet chaîne n'est pas recréé ici.
Pour vérifier si str1 et str2 pointent vers le même objet, on peut utiliser ce code
Copiez le code comme suit :
System.out.println(str1 == str2);
Le résultat est vrai.
Créer en utilisant nouveau
Copiez le code comme suit :
String str3 = new String("droïde");
Lorsque nous utilisons new pour construire un objet chaîne, un nouvel objet chaîne sera créé, qu'il existe ou non une référence à un objet avec le même contenu dans le pool de constantes chaîne. Nous utilisons donc le code suivant pour le tester,
Copiez le code comme suit :
String str3 = new String("droïde");
System.out.println(str1 == str3);
Le résultat est faux comme nous le pensions, indiquant que les deux variables pointent vers des objets différents.
interne
Pour l'objet chaîne créé à l'aide de new ci-dessus, si vous souhaitez ajouter la référence de cet objet au pool de constantes chaîne, vous pouvez utiliser la méthode interne.
Après avoir appelé stagiaire, vérifiez d'abord s'il existe une référence à l'objet dans le pool de constantes de chaîne. S'il existe, renvoyez la référence à la variable. Sinon, ajoutez la référence et renvoyez-la à la variable.
Copiez le code comme suit :
Chaîne str4 = str3.intern();
System.out.println(str4 == str1);
Le résultat de sortie est vrai.
Questions difficiles
Condition préalable?
La condition préalable à l'implémentation du pool de constantes de chaîne est que l'objet String en Java soit immuable, ce qui peut garantir en toute sécurité que plusieurs variables partagent le même objet. Si l'objet String en Java est mutable et qu'une opération de référence modifie la valeur de l'objet, d'autres variables seront également affectées.
référence ou objet
Le problème le plus courant est de savoir si les références ou les objets sont stockés dans le pool de constantes de chaîne. Le pool de constantes de chaîne stocke les références d’objets, pas les objets. En Java, les objets sont créés dans la mémoire tas.
Vérification de la mise à jour, de nombreux commentaires reçus abordent également ce problème, je l'ai simplement vérifié. Environnement de vérification :
Copiez le code comme suit :
22:18:54-androidyue~/Vidéos$ cat /etc/os-release
NOM=Fedora
VERSION="17 (Miracle costaud)"
ID=fedora
VERSION_ID=17
PRETTY_NAME="Fedora 17 (Miracle costaud)"
ANSI_COLOR="0;34"
CPE_NAME="cpe:/o:fedoraproject:fedora:17"
22:19:04-androidyue~/Vidéos$ java -version
version java "1.7.0_25"
Environnement d'exécution OpenJDK (fedora-2.3.12.1.fc17-x86_64)
VM serveur OpenJDK 64 bits (build 23.7-b01, mode mixte)
Idée de vérification : le programme Java suivant lit un fichier vidéo d'une taille de 82 Mo et effectue des opérations internes sous forme de chaînes.
Copiez le code comme suit :
22:01:17-androidyue~/Vidéos$ ll -lh | grep Why_to_learn.mp4
-rw-rw-r--.1 androidyue androidyue 82M 20 octobre 2013 Why_to_learn.mp4
Le code de vérification
Copiez le code comme suit :
importer java.io.BufferedReader ;
importer java.io.FileNotFoundException ;
importer java.io.FileReader ;
importer java.io.IOException ;
classe publique TestMain {
chaîne statique privée fileContent ;
public static void main (String[] arguments) {
fileContent = readFileToString(args[0]);
si (null != fileContent) {
fileContent = fileContent.intern();
System.out.println("Non nul");
}
}
chaîne statique privée readFileToString (fichier de chaîne) {
Lecteur BufferedReader = null ;
essayer {
lecteur = nouveau BufferedReader (nouveau FileReader (fichier));
StringBufferbuff = new StringBuffer();
Ligne de ficelle ;
while ((line = reader.readLine()) != null) {
buff.append(ligne);
}
return buff.toString();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} enfin {
if (null != lecteur) {
essayer {
lecteur.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
renvoie null ;
}
}
Étant donné que le pool de constantes de chaîne existe dans la génération permanente dans la mémoire tas, il est applicable avant Java8. Nous avons vérifié cela en fixant la génération permanente à une très petite valeur. Si l'objet chaîne existe dans le pool de constantes chaîne, alors l'erreur d'espace java.lang.OutOfMemoryError permgen sera inévitablement générée.
Copiez le code comme suit :
java -XX:PermSize=6m TestMain ~/Videos/why_to_learn.mp4
L'exécution du programme de preuve n'a pas généré de MOO. En fait, cela ne peut pas très bien prouver si des objets ou des références sont stockés.
Mais cela prouve au moins que l'objet de contenu réel char[] de la chaîne n'est pas stocké dans le pool de constantes de chaîne. Dans ce cas, il n'est en fait pas si important que le pool de constantes de chaîne stocke des objets chaîne ou des références à des objets chaîne. Mais personnellement, je préfère quand même le stocker comme référence.
Avantages et inconvénients
L'avantage du pool de constantes de chaîne est de réduire la création de chaînes avec le même contenu et d'économiser de l'espace mémoire.
Si l’on insiste pour parler des inconvénients, c’est que le temps de calcul CPU est sacrifié en échange d’espace. Le temps de calcul du CPU est principalement utilisé pour déterminer s'il existe une référence à un objet avec le même contenu dans le pool de constantes de chaîne. Cependant, son implémentation interne est HashTable, le coût de calcul est donc faible.
Recyclage des GC ?
Étant donné que le pool de constantes de chaîne contient des références à des objets chaîne partagés, cela signifie-t-il que ces objets ne peuvent pas être recyclés ?
Tout d’abord, les objets partagés en question sont généralement relativement petits. Pour autant que je sache, ce problème existait dans les versions antérieures, mais avec l'introduction de références faibles, ce problème devrait désormais disparaître.
Concernant cette problématique, vous pouvez en savoir plus sur cet article interné Strings : Java Glossary
utilisation interne ?
La condition préalable pour utiliser stagiaire est que vous sachiez que vous en avez vraiment besoin. Par exemple, nous avons des millions d'enregistrements ici, et une certaine valeur dans l'enregistrement est plusieurs fois Californie, États-Unis. Nous ne voulons pas créer des millions de ces objets chaîne. Nous pouvons utiliser interne pour conserver une seule copie en mémoire. Peut. Pour une compréhension plus approfondie de stagiaire, veuillez vous référer à Analyse approfondie de String#intern.
Y a-t-il toujours des exceptions ?
Savez-vous que le code suivant créera plusieurs objets chaîne et enregistrera plusieurs références dans le pool de constantes chaîne ?
Copiez le code comme suit :
Test de chaîne = "a" + "b" + "c" ;
La réponse est qu’un seul objet est créé et qu’une seule référence est enregistrée dans le pool constant. Nous pouvons le découvrir en utilisant javap pour décompiler et jeter un œil.
Copiez le code comme suit :
17:02 $ javap -c TestInternedPoolGC
Compilé à partir de "TestInternedPoolGC.java"
la classe publique TestInternedPoolGC étend java.lang.Object{
public TestInternedPoolGC();
Code:
0 : aload_0
1 : invocationspecial #1 ; //Méthode java/lang/Object."<init>":()V
4 : retour
public static void main(java.lang.String[]) lance java.lang.Exception ;
Code:
0 : ldc #2 ; //Chaîne abc
2 : astore_1
3 : retour
Avez-vous vu que lors de la compilation, ces trois littéraux ont été combinés en un seul ? Il s'agit en fait d'une optimisation qui évite la création d'objets chaînes redondants et ne provoque pas de problèmes d'épissage de chaînes. Concernant l'épissage de chaînes, vous pouvez afficher les détails Java : Épissage de chaînes.