Selon String # intern () , la méthode intern
est censée renvoyer la chaîne du pool String si la chaîne est trouvée dans le pool String, sinon un nouvel objet chaîne sera ajouté. Le pool de chaînes et la référence de cette chaîne sont renvoyés.
Alors j'ai essayé ceci:
String s1 = "Rakesh";
String s2 = "Rakesh";
String s3 = "Rakesh".intern();
if ( s1 == s2 ){
System.out.println("s1 and s2 are same"); // 1.
}
if ( s1 == s3 ){
System.out.println("s1 and s3 are same" ); // 2.
}
Je m'attendais à ça s1 and s3 are same
sera imprimé lors de l'internalisation de s3 et s1 and s2 are same
ne sera pas imprimé. Mais le résultat est: les deux lignes sont imprimées. Cela signifie donc que, par défaut, les constantes de chaîne sont internées. Mais s'il en est ainsi, pourquoi avons-nous besoin de la méthode intern
? En d'autres termes, quand devrions-nous utiliser cette méthode?
Java interne automatiquement les littéraux de chaîne. Cela signifie que dans de nombreux cas, l'opérateur == semble fonctionner pour Strings de la même manière que pour les ints ou autres valeurs primitives.
Comme interning est automatique pour les littéraux de chaîne, la méthode intern()
doit être utilisée sur les chaînes construites avec new String()
.
En utilisant votre exemple:
String s1 = "Rakesh";
String s2 = "Rakesh";
String s3 = "Rakesh".intern();
String s4 = new String("Rakesh");
String s5 = new String("Rakesh").intern();
if ( s1 == s2 ){
System.out.println("s1 and s2 are same"); // 1.
}
if ( s1 == s3 ){
System.out.println("s1 and s3 are same" ); // 2.
}
if ( s1 == s4 ){
System.out.println("s1 and s4 are same" ); // 3.
}
if ( s1 == s5 ){
System.out.println("s1 and s5 are same" ); // 4.
}
reviendra:
s1 and s2 are same
s1 and s3 are same
s1 and s5 are same
Reportez-vous à JavaTechniques "Égalité des chaînes et interning" pour plus d'informations.
Sur un projet récent, de très grandes structures de données ont été configurées avec des données extraites d'une base de données (et donc pas des constantes/littéraux de chaîne), mais avec une énorme quantité de duplication. C’était une application bancaire, et des noms comme ceux d’un groupe modeste (peut-être 100 ou 200) apparaissaient un peu partout. Les structures de données étaient déjà volumineuses et si tous ces noms de corp avaient été des objets uniques, ils auraient saturé la mémoire. Au lieu de cela, toutes les structures de données avaient des références aux mêmes objets 100 ou 200 String, économisant ainsi beaucoup d'espace.
Un autre petit avantage des chaînes internes est que ==
peut être utilisé (avec succès!) pour comparer des chaînes s'il est garanti que toutes les chaînes impliquées sont internées. Outre la syntaxe allégée, il s'agit également d'une amélioration des performances. Mais Comme l'ont déjà souligné d'autres personnes, cela risquerait fort de générer des erreurs de programmation. Par conséquent, cela ne devrait être fait qu'en dernier recours.
L'inconvénient est que l'internation d'une chaîne prend plus de temps que de la jeter simplement sur le tas, et que l'espace pour les chaînes internées peut être limité, en fonction de l'implémentation de Java. C'est mieux lorsque vous ' Nous traitons avec un nombre raisonnable connu de chaînes avec beaucoup de duplications.
Je veux ajouter mes 2 cents sur l'utilisation de ==
avec des chaînes internes.
La première chose String.equals
fait est this==object
.
Ainsi, bien qu’il y ait un gain de performances minuscule (vous n’appelez pas de méthode), du point de vue du responsable, utilisez ==
est un cauchemar, car certaines chaînes internées ont tendance à devenir non-internées.
Je suggère donc de ne pas compter sur le cas particulier de ==
pour les chaînes internées, mais utilisez toujours equals
comme prévu par Gosling.
EDIT: interné devenant non-interné:
V1.0
public class MyClass
{
private String reference_val;
...
private boolean hasReferenceVal ( final String[] strings )
{
for ( String s : strings )
{
if ( s == reference_val )
{
return true;
}
}
return false;
}
private void makeCall ( )
{
final String[] interned_strings = { ... init with interned values ... };
if ( hasReference( interned_strings ) )
{
...
}
}
}
Dans la version 2.0, le responsable a décidé de rendre hasReferenceVal
public, sans entrer dans les détails car il attend un tableau de chaînes internées.
V2.0
public class MyClass
{
private String reference_val;
...
public boolean hasReferenceVal ( final String[] strings )
{
for ( String s : strings )
{
if ( s == reference_val )
{
return true;
}
}
return false;
}
private void makeCall ( )
{
final String[] interned_strings = { ... init with interned values ... };
if ( hasReference( interned_strings ) )
{
...
}
}
}
Maintenant, vous avez un bogue, ce qui peut être très difficile à trouver, car dans la plupart des cas, tableau contient des valeurs littérales, et parfois une chaîne non littérale est utilisée. Si equals
a été utilisé à la place de ==
alors hasReferenceVal
aurait toujours continuer à fonctionner. Encore une fois, les gains de performances sont minimes, mais les coûts de maintenance sont élevés.
Les littéraux de chaîne et les constantes sont internés par défaut. C'est-à-dire, "foo" == "foo"
(Déclaré par les littéraux de chaîne), mais new String("foo") != new String("foo")
.
Les chaînes dans Java sont des objets immuables par conception. Par conséquent, deux objets chaîne, même avec la même valeur, seront des objets différents par défaut. Toutefois, si nous souhaitons économiser de la mémoire, nous pourrions indiquer d'utiliser la même mémoire. par un concept appelé chaîne intern.
Les règles ci-dessous vous aideraient à comprendre le concept en termes clairs:
Exemple:
String s1=new String (“abc”);
String s2=new String (“abc”);
If (s1==s2) //would return false by rule #4
If (“abc” == “a”+”bc” ) //would return true by rules #2 and #3
If (“abc” == s1 ) //would return false by rules #1,2 and #4
If (“abc” == s1.intern() ) //would return true by rules #1,2,4 and #6
If ( s1 == s2.intern() ) //wound return false by rules #1,4, and #6
Remarque: Les cas de motivation pour string intern ne sont pas abordés ici. Cependant, économiser de la mémoire sera certainement l'un des objectifs principaux.
vous devez établir deux périodes, qui sont la compilation et la durée d'exécution. Par exemple:
//example 1
"test" == "test" // --> true
"test" == "te" + "st" // --> true
//example 2
"test" == "!test".substring(1) // --> false
"test" == "!test".substring(1).intern() // --> true
d’une part, dans l’exemple 1, nous trouvons que les résultats sont tous vrais, car lors de la compilation, jvm mettra le "test" dans le pool de chaînes littérales, si la recherche "test" existe, alors il utilisera l'existant, dans l'exemple 1, les chaînes "test" pointent toutes vers la même adresse mémoire, de sorte que l'exemple 1 renvoie true. d'autre part, dans l'exemple 2, la méthode de substring () s'exécute dans le temps d'exécution, dans le cas de "test" == "! test" .substring (1), le pool créera deux objets chaîne, " test "et"! test ", ce sont donc des objets de référence différents, donc ce cas retournera false, dans le cas de" test "=="! test ".substring (1) .intern (), la méthode de intern ( ) mettra le ""! test ".substring (1)" dans le pool de chaînes littérales, de sorte que dans ce cas, ce sont les mêmes objets de référence, donc ils renverront true.
http://en.wikipedia.org/wiki/String_interning
chaîne interning est une méthode de stockage d'une seule copie de chaque valeur de chaîne distincte, qui doit être immuable. L'internalisation des chaînes permet à certaines tâches de traitement de chaînes de gagner du temps ou de gagner de la place, au lieu de prendre plus de temps lorsque la chaîne est créée ou internée. Les valeurs distinctes sont stockées dans un pool interne de chaînes.
public static void main(String[] args) {
// TODO Auto-generated method stub
String s1 = "test";
String s2 = new String("test");
System.out.println(s1==s2); //false
System.out.println(s1==s2.intern()); //true --> because this time compiler is checking from string constant pool.
}
String s1 = "Anish";
String s2 = "Anish";
String s3 = new String("Anish");
/*
* When the intern method is invoked, if the pool already contains a
* string equal to this String object as determined by the
* method, then the string from the pool is
* returned. Otherwise, this String object is added to the
* pool and a reference to this String object is returned.
*/
String s4 = new String("Anish").intern();
if (s1 == s2) {
System.out.println("s1 and s2 are same");
}
if (s1 == s3) {
System.out.println("s1 and s3 are same");
}
if (s1 == s4) {
System.out.println("s1 and s4 are same");
}
SORTIE
s1 and s2 are same
s1 and s4 are same
Les chaînes internées évitent les chaînes en double. Interning enregistre RAM aux dépens de plus de temps CPU pour détecter et remplacer les chaînes en double. Il n'y a qu'une seule copie de chaque chaîne qui a été internée, quel que soit le nombre de références qui la pointent. Depuis Strings sont immuables, si deux méthodes différentes utilisent incidemment la même chaîne, elles peuvent partager une copie de la même chaîne.Le processus de conversion des chaînes dupliquées en chaînes partagées est appelé interning.String.intern () vous donne l'adresse de la chaîne maître canonique. Vous pouvez comparer des chaînes internées avec simple == (qui compare les pointeurs) au lieu de est égal à qui compare les caractères de la chaîne un à un, car les chaînes sont immuables, le processus intern est libre de gagner de la place, par exemple en ne créant pas de littéral chaîne distinct pour "pot" lorsqu'il existe en tant que sous-chaîne d'un autre littéral tel que "hippopotame".
Pour en voir plus http://mindprod.com/jgloss/interned.html
String p1 = "example";
String p2 = "example";
String p3 = "example".intern();
String p4 = p2.intern();
String p5 = new String(p3);
String p6 = new String("example");
String p7 = p6.intern();
if (p1 == p2)
System.out.println("p1 and p2 are the same");
if (p1 == p3)
System.out.println("p1 and p3 are the same");
if (p1 == p4)
System.out.println("p1 and p4 are the same");
if (p1 == p5)
System.out.println("p1 and p5 are the same");
if (p1 == p6)
System.out.println("p1 and p6 are the same");
if (p1 == p6.intern())
System.out.println("p1 and p6 are the same when intern is used");
if (p1 == p7)
System.out.println("p1 and p7 are the same");
Lorsque deux chaînes sont créées indépendamment, intern()
vous permet de les comparer et vous aide également à créer une référence dans le pool de chaînes si la référence n'existait pas auparavant.
Lorsque vous utilisez String s = new String(hi)
, Java crée une nouvelle instance de la chaîne, mais lorsque vous utilisez String s = "hi"
, Java vérifie s'il existe ou non une instance de Word "hi" dans le code et si elle existe, elle renvoie simplement la référence.
Étant donné que la comparaison de chaînes est basée sur une référence, intern()
vous aide à créer une référence et vous permet de comparer le contenu des chaînes.
Lorsque vous utilisez intern()
dans le code, l'espace utilisé par la chaîne faisant référence au même objet est effacé et ne renvoie que la référence du même objet existant en mémoire.
Mais dans le cas de p5 lorsque vous utilisez:
String p5 = new String(p3);
Seul le contenu de p3 est copié et p5 est créé récemment. Donc ce n'est pas interned.
Donc, le résultat sera:
p1 and p2 are the same
p1 and p3 are the same
p1 and p4 are the same
p1 and p6 are the same when intern is used
p1 and p7 are the same
la méthode string intern () est utilisée pour créer une copie exacte de l'objet chaîne de tas dans le pool de constantes de chaînes. Les objets chaîne dans le pool de constantes chaîne sont automatiquement internés, mais pas les objets chaîne dans tas. L’utilisation principale de la création de stagiaires consiste à économiser l’espace mémoire et à comparer plus rapidement les objets chaîne.
Comme vous l'avez dit, cette méthode string intern()
trouvera d'abord dans le pool String, si elle le trouve, elle retournera ensuite l'objet qui pointe vers celui-ci ou ajoutera une nouvelle chaîne au pool.
String s1 = "Hello";
String s2 = "Hello";
String s3 = "Hello".intern();
String s4 = new String("Hello");
System.out.println(s1 == s2);//true
System.out.println(s1 == s3);//true
System.out.println(s1 == s4.intern());//true
Les s1
Et s2
Sont deux objets pointant vers le pool de chaînes "Hello", et l'utilisation de "Hello".intern()
permet de trouver que s1
Et s2
. Ainsi, "s1 == s3"
Renvoie la valeur true, ainsi que la fonction s3.intern()
.