Qu'est-ce que String Interning en Java, quand dois-je l'utiliser et pourquoi ?
java
string
string-interning
saplingPro
la source
la source
String a = new String("abc");
String b = new String("abc");
alorsa.intern() == b.intern()
String.intern()
dépendClassLoader
, ce qui signifie, Est-ce que différents chargeurs de classe créent des "différents"String
, provoquant desintern
s différents ?Réponses:
http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#intern ()
Fondamentalement, faire String.intern () sur une série de chaînes garantira que toutes les chaînes ayant le même contenu partagent la même mémoire. Donc, si vous avez une liste de noms où 'john' apparaît 1000 fois, en interne vous vous assurez qu'un seul 'john' est réellement alloué à la mémoire.
Cela peut être utile pour réduire les besoins en mémoire de votre programme. Mais sachez que le cache est maintenu par la machine virtuelle Java dans un pool de mémoire permanente qui est généralement de taille limitée par rapport au tas, vous ne devez donc pas utiliser interne si vous n'avez pas trop de valeurs en double.
En savoir plus sur les contraintes de mémoire liées à l'utilisation de intern ()
- De: http://www.codeinstructions.com/2009/01/busting-javalangstringintern-myths.html
Depuis JDK 7 (je veux dire dans HotSpot), quelque chose a changé.
- Depuis Java SE 7 Fonctionnalités et améliorations
Mise à jour: les chaînes internées sont stockées dans le tas principal à partir de Java 7. http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html#jdk7changes
la source
char[]
au lieu deString
pour le texte sensible et de le mettre à zéro dès qu'il n'est plus nécessaire.Il y a des questions "d'interview accrocheuses", comme pourquoi vous obtenez des égaux! si vous exécutez le morceau de code ci-dessous.
Si vous souhaitez comparer des chaînes, vous devez les utiliser
equals()
. Ce qui précède s'imprimera égal car letestString
est déjà interné pour vous par le compilateur. Vous pouvez interner les chaînes vous-même en utilisant la méthode interne comme indiqué dans les réponses précédentes ....la source
equals
méthode. Vous voudrez peut-être ajouter unenew String()
comparaison pour montrer plus clairement la distinction.JLS
JLS 7 3.10.5 le définit et donne un exemple pratique:
JVMS
JVMS 7 5.1 dit que l'internement est implémenté de manière magique et efficace avec une
CONSTANT_String_info
structure dédiée (contrairement à la plupart des autres objets qui ont des représentations plus génériques):Bytecode
Décompilons du bytecode OpenJDK 7 pour voir l'internement en action.
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
Mise à jour pour Java 8 ou plus . Dans Java 8, l'espace PermGen (génération permanente) est supprimé et remplacé par Meta Space. La mémoire du pool de chaînes est déplacée vers le tas de JVM.
Par rapport à Java 7, la taille du pool de chaînes est augmentée dans le tas. Par conséquent, vous disposez de plus d'espace pour les chaînes internalisées, mais vous disposez de moins de mémoire pour l'ensemble de l'application.
Encore une chose, vous savez déjà que lors de la comparaison de 2 (références de) objets en Java, '
==
' est utilisé pour comparer la référence de l'objet, 'equals
' est utilisé pour comparer le contenu de l'objet.Vérifions ce code:
Résultat:
value1 == value2
---> vraivalue1 == value3
---> fauxvalue1.equals(value3)
---> vraivalue1 == value3.intern()
---> vraiC'est pourquoi vous devez utiliser '
equals
' pour comparer 2 objets String. Et voilà commentintern()
est utile.la source
L'internement de chaînes est une technique d'optimisation du compilateur. Si vous avez deux littéraux de chaîne identiques dans une unité de compilation, le code généré garantit qu'il n'y a qu'un seul objet chaîne créé pour toute l'instance de ce littéral (caractères entre guillemets) dans l'assembly.
Je viens du milieu C #, donc je peux expliquer en donnant un exemple à partir de cela:
sortie des comparaisons suivantes:
Remarque 1 : Les objets sont comparés par référence.
Remarque 2 : typeof (int) .Name est évalué par la méthode de réflexion afin qu'il ne soit pas évalué au moment de la compilation. Ici, ces comparaisons sont faites au moment de la compilation.
Analyse des résultats: 1) vrai car ils contiennent tous les deux le même littéral et donc le code généré n'aura qu'un seul objet référençant "Int32". Voir note 1 .
2) vrai parce que le contenu des deux valeurs est vérifié, ce qui est le même.
3) FAUX car str2 et obj n'ont pas le même littéral. Voir note 2 .
la source
la source
À partir du livre Deshmukh du programmeur OCP Java SE 11, j'ai trouvé l'explication la plus simple pour l'internement qui s'est déroulée comme suit: puisque les chaînes sont des objets et que tous les objets en Java sont toujours stockés uniquement dans l'espace de tas, toutes les chaînes sont stockées dans l'espace de tas. Cependant, Java conserve les chaînes créées sans utiliser le nouveau mot clé dans une zone spéciale de l'espace de tas, appelée "pool de chaînes". Java conserve les chaînes créées à l'aide du nouveau mot clé dans l'espace de tas normal.
L'objectif du pool de chaînes est de conserver un ensemble de chaînes uniques. Chaque fois que vous créez une nouvelle chaîne sans utiliser le nouveau mot clé, Java vérifie si la même chaîne existe déjà dans le pool de chaînes. Si tel est le cas, Java renvoie une référence au même objet String et si ce n'est pas le cas, Java crée un nouvel objet String dans le pool de chaînes et renvoie sa référence. Ainsi, par exemple, si vous utilisez deux fois la chaîne "bonjour" dans votre code, comme indiqué ci-dessous, vous obtiendrez une référence à la même chaîne. Nous pouvons réellement tester cette théorie en comparant deux variables de référence différentes en utilisant l' opérateur == comme indiqué dans le code suivant:
L' opérateur == vérifie simplement si deux références pointent vers le même objet ou non et renvoie vrai si c'est le cas. Dans le code ci-dessus, str2 obtient la référence au même objet String qui a été créé précédemment. Cependant, str3 et str4 obtiennent des références à deux objets String entièrement différents. C'est pourquoi str1 == str2 renvoie true mais str1 == str3 et str3 == str4 renvoie false. En fait, lorsque vous faites une nouvelle chaîne ("bonjour"); deux objets String sont créés au lieu d'un seul si c'est la première fois que la chaîne "hello" est utilisée dans le programme n'importe où - un dans le pool de chaînes en raison de l'utilisation d'une chaîne entre guillemets et un dans l'espace de tas normal car de l'utilisation d'un nouveau mot-clé.
Le regroupement de chaînes est la façon dont Java économise la mémoire du programme en évitant la création de plusieurs objets String contenant la même valeur. Il est possible d'obtenir une chaîne du pool de chaînes pour une chaîne créée à l'aide du nouveau mot clé en utilisant la méthode intern de String. Il est appelé «internement» d'objets chaîne. Par exemple,
la source