web-dev-qa-db-fra.com

Quand devrions-nous utiliser la méthode intern of String sur les littéraux de chaîne

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?

182
Rakesh Juyal

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.

224

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.

19
Carl Smotricz

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.

14

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").

12
Bozho

Learn Java String Intern - une fois pour toutes

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:

  1. La classe String maintient un pool interne initialement vide. Ce pool doit garantir la présence d'objets chaîne avec des valeurs uniques.
  2. Tous les littéraux de chaîne ayant la même valeur doivent être considérés comme le même objet emplacement de mémoire car ils n'ont par ailleurs aucune notion de distinction. Par conséquent, tous ces littéraux avec la même valeur feront une seule entrée dans le pool interne et feront référence au même emplacement mémoire.
  3. La concaténation de deux ou plusieurs littéraux est également un littéral. (Par conséquent, la règle n ° 2 leur sera applicable)
  4. Chaque chaîne créée en tant qu’objet (c’est-à-dire par une autre méthode que littérale) aura différents emplacements de mémoire et ne fera aucune entrée dans le pool interne.
  5. La concaténation de littéraux avec des non-littéraux en fera un non-littéral. Ainsi, l'objet résultant aura un nouvel emplacement de mémoire et NE fera PAS une entrée dans le pool interne.
  6. En appelant la méthode intern sur un objet chaîne, vous créez un nouvel objet qui entre dans le pool interne ou vous renvoyez un objet existant du pool qui a la même valeur. L'appel sur un objet qui n'est pas dans le pool interne ne déplace PAS l'objet dans le pool. Cela crée plutôt un autre objet qui entre dans la piscine.

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.

6
KGhatak

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.

4
thinkinjava

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.

3
bbcbcgb
    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.
}
2
Anurag_BEHS
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
2
anish

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

2
inter18099
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
2
raja emani

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.

Source: Qu'est-ce que string intern en java?

1
user2485429

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().

1
WendellWu