Maison  >  Article  >  Java  >  Analyse approfondie de la méthode intern() en Java

Analyse approfondie de la méthode intern() en Java

Y2J
Y2Joriginal
2017-05-19 09:47:332334parcourir

1. Problèmes de chaînes

Les chaînes sont en fait très utiles dans notre travail de codage quotidien, et elles sont relativement simples à utiliser, donc peu de gens font quelque chose de spécial à leur sujet. recherche. En revanche, les entretiens ou les tests écrits impliquent souvent des questions plus approfondies et plus difficiles. Lors du recrutement, je pose occasionnellement des questions pertinentes aux candidats. Cela ne signifie pas que les réponses doivent être particulièrement correctes et approfondies. Habituellement, le but de poser ces questions est double. Le premier est de tester la compréhension des connaissances de base. de JAVA. La seconde consiste à tester les connaissances de base de JAVA. La seconde consiste à examiner l'attitude du candidat à l'égard de la technologie.

Voyons ce que le programme suivant va produire ? Si vous pouvez répondre correctement à chaque question et savoir pourquoi, cet article ne vous dira pas grand-chose. Si la réponse est incorrecte ou si le principe n’est pas très clair, examinez de plus près l’analyse suivante. Cet article devrait vous aider à comprendre clairement les résultats de chaque programme et les raisons profondes de la publication des résultats.

Segment de code un :

package com.paddx.test.string;
public class StringTest {
    public static void main(String[] args) {
        String str1 = "string";
        String str2 = new String("string");
        String str3 = str2.intern();
 
        System.out.println(str1==str2);//#1
        System.out.println(str1==str3);//#2
    }
}

Segment de code deux :

package com.paddx.test.string;
public class StringTest01 {
    public static void main(String[] args) {
        String baseStr = "baseStr";
        final String baseFinalStr = "baseStr";
 
        String str1 = "baseStr01";
        String str2 = "baseStr"+"01";
        String str3 = baseStr + "01";
        String str4 = baseFinalStr+"01";
        String str5 = new String("baseStr01").intern();
 
        System.out.println(str1 == str2);//#3
        System.out.println(str1 == str3);//#4
        System.out.println(str1 == str4);//#5
        System.out.println(str1 == str5);//#6
    }
}

Segment de code trois (1) :

package com.paddx.test.string;  
public class InternTest {
    public static void main(String[] args) {
 
        String str2 = new String("str")+new String("01");
        str2.intern();
        String str1 = "str01";
        System.out.println(str2==str1);//#7
    }
}

Segment de code Trois (2) :

package com.paddx.test.string;
 
public class InternTest01 {
    public static void main(String[] args) {
        String str1 = "str01";
        String str2 = new String("str")+new String("01");
        str2.intern();
        System.out.println(str2 == str1);//#8
    }
}

Pour faciliter la description, j'ai encodé les résultats de sortie du code ci-dessus de #1~#8, et la partie de police bleue ci-dessous est le résultat.

2. Analyse approfondie des chaînes

1. Analyse du segment de code 1

Les chaînes n'appartiennent pas aux types de base, mais elles peuvent être comme des types de base. Attribuez directement une valeur via un littéral, bien sûr, vous pouvez également générer une chaîne objet via new. Cependant, il existe une différence essentielle entre générer des chaînes par affectation littérale et new :

Analyse approfondie de la méthode intern() en Java

Lors de la création d'une chaîne par affectation littérale, la priorité sera donnée aux constantes Vérifiez si la même chaîne existe déjà dans le pool . Si elle existe déjà, la référence dans la pile pointe directement vers la chaîne si elle n'existe pas, une chaîne est générée dans le pool constant puis La référence sur la pile pointe vers cette chaîne. Lors de la création d'une chaîne via new, un objet chaîne est directement généré dans le tas (notez qu'après JDK 7, HotSpot a transféré le pool de constantes de la génération permanente vers le tas. Pour des informations détaillées, veuillez vous référer à "Mémoire JDK8 Model-The Disagging PermGen"), la référence dans la pile pointe vers l'objet. Pour les objets chaîne dans le tas, vous pouvez ajouter la chaîne au pool de constantes via la méthode intern() et renvoyer une référence à la constante.

Maintenant, nous devrions être capables de comprendre clairement le résultat du segment de code 1 :

Résultat n°1 : Parce que str1 pointe vers une constante dans la chaîne, str2 est un objet généré dans le tas, donc str1==str2 renvoie false.

Résultat n°2 : str2 appelle la méthode interne, qui copiera la valeur de str2 ("string") dans le pool de constantes, mais la chaîne existe déjà dans le pool de constantes (c'est-à-dire que la chaîne pointe vers par str1), donc renvoie directement une référence à la chaîne, donc str1==str2 renvoie vrai.

Les résultats suivants de l'exécution du segment de code un :

Analyse approfondie de la méthode intern() en Java

2. Analyse du segment de code deux

Pour Le résultat du deuxième segment de code est plus facile à comprendre en décompilant le fichier StringTest01.class :

Contenu du pool constant (partie) :

Analyse approfondie de la méthode intern() en Java

Instruction d'exécution ( part), la deuxième colonne #+ordinal correspond à l'élément dans le pool constant) :

Analyse approfondie de la méthode intern() en Java

Avant d'expliquer le processus d'exécution ci-dessus, comprenez d'abord les deux instructions :

ldc : Poussez l'élément du pool de constantes d'exécution, chargez la référence de l'élément spécifié du pool de constantes vers la pile.

astore_ : stocke la référence dans une variable locale, attribue la référence à la nième variable locale .

Nous commençons maintenant à expliquer le processus d'exécution du segment de code 2 :

0 : ldc               #2 : Chargez le deuxième élément ("baseStr") du pool de constantes dans la pile.

2 : astore_1 : Attribue la référence en 1 à la première variable locale, c'est-à-dire String baseStr = "baseStr"

3 : ldc #2 : Charge la seconde dans la constante ; pool item("baseStr") sur la pile.

5 : astore_2 : Attribuez la référence en 3 à la deuxième variable locale, c'est-à-dire la chaîne finale baseFinalStr="baseStr" ;

6 : ldc #3 : Chargez la première chaîne dans le pool constant Trois éléments ("baseStr01") sont ajoutés à la pile.

8 : astore_3 : Attribue la référence en 6 à la troisième variable locale, à savoir String str1="baseStr01";

9 : ldc #3 : Chargez le troisième élément ("baseStr01") du pool de constantes dans la pile.

11 : astore 4 : Attribuez la référence en 9 à la quatrième variable locale : String str2="baseStr01" ;

Résultat n°3 : str1==str2 retournera certainement true , car les deux str1 et str2 pointent vers la même adresse de référence dans le pool constant. Donc en fait, après JAVA 1.6, l'opération "+" d'une chaîne constante sera directement synthétisée en chaîne lors de la phase de compilation.

13 : nouveau           #4 : Générer une instance de StringBuilder.

16 : dup : Copiez la référence de l'objet généré par 13 et poussez-le sur la pile.

17 : invokespecial #5 : Appelez le cinquième élément du pool de constantes, la méthode StringBuilder.

Les trois instructions ci-dessus sont utilisées pour générer un objet StringBuilder.

20 : aload_1  : Charge la valeur du premier paramètre, qui est "baseStr"

21 : Invoquervirtual #6 : Appeler la méthode append de l'objet StringBuilder.

24 : ldc #7 : Chargez le septième élément ("01") du pool de constantes dans la pile.

26 : invoquervirtual #6 : Appelez la méthode StringBuilder.append.

29 : invokevirtual #8 : Appelez la méthode StringBuilder.toString.

32 : astore 5 : modifiez l'affectation de la référence du résultat dans 29 à la cinquième variable locale, c'est-à-dire l'affectation à la variable str3.

Résultat n°4 : Comme str3 est en fait le résultat généré par stringBuilder.append(), il n'est pas égal à str1 et le résultat renvoie false.

34 : ldc #3 : Chargez le troisième élément ("baseStr01") du pool de constantes dans la pile.

36 : astore 6 : Attribuez la référence en 34 à la sixième variable locale, c'est-à-dire str4="baseStr01";

Résultat n°5 : Parce que str1 et str4 pointent vers des constantes La troisième élément dans le pool, donc str1==str4 renvoie true. Ici, nous pouvons également trouver un phénomène : pour les champs finaux, le remplacement constant est effectué directement au moment de la compilation, tandis que pour les champs non finaux, le traitement de l'affectation est effectué au moment de l'exécution.

38 : nouveau #9 : Créer un objet String

41 : dup : Copiez la référence et placez-la sur la pile.

42 : ldc #3 : Chargez le troisième élément ("baseStr01") du pool de constantes dans la pile.

44 : invokespecial #10 : Appelez la méthode String."" et transmettez la référence à l'étape 42 en tant que paramètre à la méthode.

47 : invokevirtual #11 : Appelez la méthode String.intern.

Le code source correspondant de 38 à 41 est new String(“baseStr01″).intern().

50 : astore 7 : attribuez le résultat renvoyé à l'étape 47 à la variable 7, c'est-à-dire que str5 pointe vers la position de baseStr01 dans le pool de constantes.

Résultat n°6 : Comme str5 et str1 pointent vers la même chaîne dans le pool de constantes, str1==str5 renvoie true.

Exécutez le segment de code deux, le résultat de sortie est le suivant :

Analyse approfondie de la méthode intern() en Java

Analyse du segment de code trois :

Pour le segment de code trois, les résultats d'exécution sont différents dans JDK 1.6 et JDK 1.7. Jetons d'abord un coup d'œil aux résultats en cours d'exécution, puis expliquons les raisons :

Résultats en cours d'exécution sous JDK 1.6 :

Analyse approfondie de la méthode intern() en Java

Résultats en cours d'exécution sous JDK 1.7 :

Analyse approfondie de la méthode intern() en Java

Selon l'analyse du segment de code 1, il devrait être facile d'obtenir le résultat du JDK 1.6, car str2 et str1 pointent à l'origine vers des emplacements différents et devraient renvoyer false.

Le problème étrange est qu'après JDK 1.7, true est renvoyé pour le premier cas, mais après avoir changé la position, le résultat renvoyé devient faux. La raison principale en est qu'après JDK 1.7, HotSpot a déplacé le pool de constantes de la génération permanente vers le métaespace. Pour cette raison, la méthode interne après JDK 1.7 a subi des changements d'implémentation relativement importants. toujours être utilisé en premier. Accédez à pour demander si existe déjà dans le pool constant. S'il existe, renvoyez la référence dans le pool constant. Ce n'est pas différent d'avant. introuvable dans le pool constant, alors la chaîne ne sera plus copiée dans le pool constant, mais une référence à la chaîne d'origine sera générée dans le pool constant. Donc :

Résultat n°7 : Dans le premier cas, comme il n'y a pas de chaîne "str01" dans le pool constant, une référence à "str01" dans le tas sera générée dans le pool constant, et lors de l'exécution affectation littérale, le pool de constantes existe déjà, la référence peut donc être renvoyée directement. Par conséquent, str1 et str2 pointent tous deux vers la chaîne dans le tas et renvoient true.

Résultat n°8 : après avoir échangé les positions, comme le pool de constantes n'existe pas lors de l'exécution d'une affectation littérale (String str1 = "str01"), str1 pointe vers la position dans le pool de constantes et str2 pointe vers le tas When. la méthode interne est utilisée pour l'objet dans , elle n'a aucun effet sur str1 et str2, donc false est renvoyé.

[Recommandations associées]

1. Tutoriel vidéo gratuit Java

2. Résumé de l'expérience d'utilisation de la méthode intern() dans. JAVA

3.Quel est le concept de méthode interne en Java

4 Analyser le rôle de intern() en Java

5. Explication détaillée de intern() dans l'objet String

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn