好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

关于java String中intern的深入讲解

本文主要研究一下 java string的 intern

string.intern()

java.base/java/lang/string.java

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

public final class string

  implements java.io.serializable, comparable<string>, charsequence,

     constable, constantdesc {

 

  //......

 

  /**

   * returns a canonical representation for the string object.

   * <p>

   * a pool of strings, initially empty, is maintained privately by the

   * class {@code string}.

   * <p>

   * when the intern method is invoked, if the pool already contains a

   * string equal to this {@code string} object as determined by

   * the {@link #equals(object)} method, then the string from the pool is

   * returned. otherwise, this {@code string} object is added to the

   * pool and a reference to this {@code string} object is returned.

   * <p>

   * it follows that for any two strings {@code s} and {@code t},

   * {@code s.intern() == t.intern()} is {@code true}

   * if and only if {@code s.equals(t)} is {@code true}.

   * <p>

   * all literal strings and string-valued constant expressions are

   * interned. string literals are defined in section 3.10.5 of the

   * <cite>the java™ language specification</cite>.

   *

   * @return a string that has the same contents as this string, but is

   *   guaranteed to be from a pool of unique strings.

   * @jls 3.10.5 string literals

   */

  public native string intern();

 

  //......  

 

}

当调用intern方法时,如果常量池已经包含一个equals此string对象的字符串,则返回池中的字符串 当调用intern方法时,如果常量池没有一个equals此string对象的字符串,将此string对象添加到池中,并返回此string对象的引用(即intern方法返回指向heap中的此string对象引用) 所有literal strings及string-valued constant expressions都是interned的

实例

基于jdk12

stringexistinpoolbeforeintern

?

1

2

3

4

5

6

7

8

9

10

public class stringexistinpoolbeforeintern {

 

  public static void main(string[] args){

   string stringobject = new string( "tomcat" );

   //note 在intern之前,string table已经有了tomcat,因而intern返回tomcat,不会指向stringobject

   stringobject.intern();

   string stringliteral = "tomcat" ;

   system.out.println(stringobject == stringliteral); //false

  }

}

tomcat这个literal string是interned过的,常量池没有tomcat,因而添加到常量池,常量池有个tomcat;另外由于stringobject是new的,所以heap中也有一个tomcat,而此时它指向heap中的tomcat stringobject.intern()返回的是heap中常量池的tomcat;stringliteral是tomcat这个literal string,由于常量池已经有该值,因而stringliteral指向的是heap中常量池的tomcat 此时stringobject指向的是heap中的tomcat,而stringliteral是heap中常量池的tomcat,因而二者不等,返回false

stringnotexistinpoolbeforeintern

?

1

2

3

4

5

6

7

8

9

10

public class stringnotexistinpoolbeforeintern {

 

  public static void main(string[] args){

   string stringobject = new string( "tom" ) + new string( "cat" );

   //note 在intern之前,string table没有tomcat,因而intern指向stringobject

   stringobject.intern();

   string stringliteral = "tomcat" ;

   system.out.println(stringobject == stringliteral); //true

  }

}

tom及cat这两个literal string是interned过的,常量池没有tom及cat,因而添加到常量池,常量池有tom、cat;另外由于stringobject是new出来的,是tom及cat二者concat,因而heap中有一个tomcat stringobject的intern方法执行的时候,由于常量池中没有tomcat,因而添加到常量池,intern()返回的是指向heap中的tomcat的引用;stringliteral是tomcat这个literal string,由于stringobject.intern()已经将tomcat添加到常量池了并指向heap中的tomcat的引用,所以stringliteral返回的是指向heap中的tomcat的引用 由于stringliteral返回的是指向heap中的tomcat的引用,其实就是stringobject,因而二者相等,返回true

javap

基于jdk12

stringexistinpoolbeforeintern

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

javac src/main/java/com/example/javac/stringexistinpoolbeforeintern.java

javap -v src/main/java/com/example/javac/stringexistinpoolbeforeintern. class

 

  last modified 2019 年 4 月 6 日; size 683 bytes

  md5 checksum 207635ffd7560f1df24b98607e2ca7db

  compiled from "stringexistinpoolbeforeintern.java"

public class com.example.javac.stringexistinpoolbeforeintern

  minor version: 0

  major version: 56

  flags: ( 0x0021 ) acc_public, acc_super

  this_class: # 8        // com/example/javac/stringexistinpoolbeforeintern

  super_class: # 9        // java/lang/object

  interfaces: 0 , fields: 0 , methods: 2 , attributes: 1

constant pool:

  # 1 = methodref   # 9 .# 21    // java/lang/object."<init>":()v

  # 2 = class     # 22    // java/lang/string

  # 3 = string    # 23    // tomcat

  # 4 = methodref   # 2 .# 24    // java/lang/string."<init>":(ljava/lang/string;)v

  # 5 = methodref   # 2 .# 25    // java/lang/string.intern:()ljava/lang/string;

  # 6 = fieldref   # 26 .# 27   // java/lang/system.out:ljava/io/printstream;

  # 7 = methodref   # 18 .# 28   // java/io/printstream.println:(z)v

  # 8 = class     # 29    // com/example/javac/stringexistinpoolbeforeintern

  # 9 = class     # 30    // java/lang/object

  # 10 = utf8    <init>

  # 11 = utf8    ()v

  # 12 = utf8    code

  # 13 = utf8    linenumbertable

  # 14 = utf8    main

  # 15 = utf8    ([ljava/lang/string;)v

  # 16 = utf8    stackmaptable

  # 17 = class     # 31    // "[ljava/lang/string;"

  # 18 = class     # 32    // java/io/printstream

  # 19 = utf8    sourcefile

  # 20 = utf8    stringexistinpoolbeforeintern.java

  # 21 = nameandtype  # 10 :# 11   // "<init>":()v

  # 22 = utf8    java/lang/string

  # 23 = utf8    tomcat

  # 24 = nameandtype  # 10 :# 33   // "<init>":(ljava/lang/string;)v

  # 25 = nameandtype  # 34 :# 35   // intern:()ljava/lang/string;

  # 26 = class     # 36    // java/lang/system

  # 27 = nameandtype  # 37 :# 38   // out:ljava/io/printstream;

  # 28 = nameandtype  # 39 :# 40   // println:(z)v

  # 29 = utf8    com/example/javac/stringexistinpoolbeforeintern

  # 30 = utf8    java/lang/object

  # 31 = utf8    [ljava/lang/string;

  # 32 = utf8    java/io/printstream

  # 33 = utf8    (ljava/lang/string;)v

  # 34 = utf8    intern

  # 35 = utf8    ()ljava/lang/string;

  # 36 = utf8    java/lang/system

  # 37 = utf8    out

  # 38 = utf8    ljava/io/printstream;

  # 39 = utf8    println

  # 40 = utf8    (z)v

{

  public com.example.javac.stringexistinpoolbeforeintern();

  descriptor: ()v

  flags: ( 0x0001 ) acc_public

  code:

   stack= 1 , locals= 1 , args_size= 1

    0 : aload_0

    1 : invokespecial # 1      // method java/lang/object."<init>":()v

    4 : return

   linenumbertable:

   line 8 : 0

 

  public static void main(java.lang.string[]);

  descriptor: ([ljava/lang/string;)v

  flags: ( 0x0009 ) acc_public, acc_static

  code:

   stack= 3 , locals= 3 , args_size= 1

    0 : new    # 2      // class java/lang/string

    3 : dup

    4 : ldc   # 3      // string tomcat

    6 : invokespecial # 4      // method java/lang/string."<init>":(ljava/lang/string;)v

    9 : astore_1

   10 : aload_1

   11 : invokevirtual # 5      // method java/lang/string.intern:()ljava/lang/string;

   14 : pop

   15 : ldc   # 3      // string tomcat

   17 : astore_2

   18 : getstatic  # 6      // field java/lang/system.out:ljava/io/printstream;

   21 : aload_1

   22 : aload_2

   23 : if_acmpne  30

   26 : iconst_1

   27 : goto    31

   30 : iconst_0

   31 : invokevirtual # 7      // method java/io/printstream.println:(z)v

   34 : return

   linenumbertable:

   line 11 : 0

   line 13 : 10

   line 14 : 15

   line 15 : 18

   line 16 : 34

   stackmaptable: number_of_entries = 2

   frame_type = 255 /* full_frame */

    offset_delta = 30

    locals = [ class "[ljava/lang/string;", class java/lang/string, class java/lang/string ]

    stack = [ class java/io/printstream ]

   frame_type = 255 /* full_frame */

    offset_delta = 0

    locals = [ class "[ljava/lang/string;" , class java/lang/string, class java/lang/string ]

    stack = [ class java/io/printstream, int ]

}

sourcefile: "stringexistinpoolbeforeintern.java"

可以看到常量池有个tomcat

stringnotexistinpoolbeforeintern

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

javac src/main/java/com/example/javac/stringnotexistinpoolbeforeintern.java

javap -v src/main/java/com/example/javac/stringnotexistinpoolbeforeintern. class

 

  last modified 2019 年 4 月 6 日; size 1187 bytes

  md5 checksum 6d173f303b61b8f5826e54bb6ed5157c

  compiled from "stringnotexistinpoolbeforeintern.java"

public class com.example.javac.stringnotexistinpoolbeforeintern

  minor version: 0

  major version: 56

  flags: ( 0x0021 ) acc_public, acc_super

  this_class: # 11        // com/example/javac/stringnotexistinpoolbeforeintern

  super_class: # 12       // java/lang/object

  interfaces: 0 , fields: 0 , methods: 2 , attributes: 3

constant pool:

  # 1 = methodref   # 12 .# 24   // java/lang/object."<init>":()v

  # 2 = class     # 25    // java/lang/string

  # 3 = string    # 26    // tom

  # 4 = methodref   # 2 .# 27    // java/lang/string."<init>":(ljava/lang/string;)v

  # 5 = string    # 28    // cat

  # 6 = invokedynamic  # 0 :# 32    // #0:makeconcatwithconstants:(ljava/lang/string;ljava/lang/string;)ljava/lang/string;

  # 7 = methodref   # 2 .# 33    // java/lang/string.intern:()ljava/lang/string;

  # 8 = string    # 34    // tomcat

  # 9 = fieldref   # 35 .# 36   // java/lang/system.out:ljava/io/printstream;

  # 10 = methodref   # 21 .# 37   // java/io/printstream.println:(z)v

  # 11 = class     # 38    // com/example/javac/stringnotexistinpoolbeforeintern

  # 12 = class     # 39    // java/lang/object

  # 13 = utf8    <init>

  # 14 = utf8    ()v

  # 15 = utf8    code

  # 16 = utf8    linenumbertable

  # 17 = utf8    main

  # 18 = utf8    ([ljava/lang/string;)v

  # 19 = utf8    stackmaptable

  # 20 = class     # 40    // "[ljava/lang/string;"

  # 21 = class     # 41    // java/io/printstream

  # 22 = utf8    sourcefile

  # 23 = utf8    stringnotexistinpoolbeforeintern.java

  # 24 = nameandtype  # 13 :# 14   // "<init>":()v

  # 25 = utf8    java/lang/string

  # 26 = utf8    tom

  # 27 = nameandtype  # 13 :# 42   // "<init>":(ljava/lang/string;)v

  # 28 = utf8    cat

  # 29 = utf8    bootstrapmethods

  # 30 = methodhandle  6 :# 43    // ref_invokestatic java/lang/invoke/stringconcatfactory.makeconcatwithconstants:(ljava/lang/invoke/methodhandles$lookup;ljava/lang/string;ljava/lang/invoke/methodtype;ljava/lang/string;[ljava/lang/object;)ljava/lang/invoke/callsite;

  # 31 = string    # 44    // \u0001\u0001

  # 32 = nameandtype  # 45 :# 46   // makeconcatwithconstants:(ljava/lang/string;ljava/lang/string;)ljava/lang/string;

  # 33 = nameandtype  # 47 :# 48   // intern:()ljava/lang/string;

  # 34 = utf8    tomcat

  # 35 = class     # 49    // java/lang/system

  # 36 = nameandtype  # 50 :# 51   // out:ljava/io/printstream;

  # 37 = nameandtype  # 52 :# 53   // println:(z)v

  # 38 = utf8    com/example/javac/stringnotexistinpoolbeforeintern

  # 39 = utf8    java/lang/object

  # 40 = utf8    [ljava/lang/string;

  # 41 = utf8    java/io/printstream

  # 42 = utf8    (ljava/lang/string;)v

  # 43 = methodref   # 54 .# 55   // java/lang/invoke/stringconcatfactory.makeconcatwithconstants:(ljava/lang/invoke/methodhandles$lookup;ljava/lang/string;ljava/lang/invoke/methodtype;ljava/lang/string;[ljava/lang/object;)ljava/lang/invoke/callsite;

  # 44 = utf8    \u0001\u0001

  # 45 = utf8    makeconcatwithconstants

  # 46 = utf8    (ljava/lang/string;ljava/lang/string;)ljava/lang/string;

  # 47 = utf8    intern

  # 48 = utf8    ()ljava/lang/string;

  # 49 = utf8    java/lang/system

  # 50 = utf8    out

  # 51 = utf8    ljava/io/printstream;

  # 52 = utf8    println

  # 53 = utf8    (z)v

  # 54 = class     # 56    // java/lang/invoke/stringconcatfactory

  # 55 = nameandtype  # 45 :# 60   // makeconcatwithconstants:(ljava/lang/invoke/methodhandles$lookup;ljava/lang/string;ljava/lang/invoke/methodtype;ljava/lang/string;[ljava/lang/object;)ljava/lang/invoke/callsite;

  # 56 = utf8    java/lang/invoke/stringconcatfactory

  # 57 = class     # 62    // java/lang/invoke/methodhandles$lookup

  # 58 = utf8    lookup

  # 59 = utf8    innerclasses

  # 60 = utf8    (ljava/lang/invoke/methodhandles$lookup;ljava/lang/string;ljava/lang/invoke/methodtype;ljava/lang/string;[ljava/lang/object;)ljava/lang/invoke/callsite;

  # 61 = class     # 63    // java/lang/invoke/methodhandles

  # 62 = utf8    java/lang/invoke/methodhandles$lookup

  # 63 = utf8    java/lang/invoke/methodhandles

{

  public com.example.javac.stringnotexistinpoolbeforeintern();

  descriptor: ()v

  flags: ( 0x0001 ) acc_public

  code:

   stack= 1 , locals= 1 , args_size= 1

    0 : aload_0

    1 : invokespecial # 1      // method java/lang/object."<init>":()v

    4 : return

   linenumbertable:

   line 8 : 0

 

  public static void main(java.lang.string[]);

  descriptor: ([ljava/lang/string;)v

  flags: ( 0x0009 ) acc_public, acc_static

  code:

   stack= 4 , locals= 3 , args_size= 1

    0 : new    # 2      // class java/lang/string

    3 : dup

    4 : ldc   # 3      // string tom

    6 : invokespecial # 4      // method java/lang/string."<init>":(ljava/lang/string;)v

    9 : new    # 2      // class java/lang/string

   12 : dup

   13 : ldc   # 5      // string cat

   15 : invokespecial # 4      // method java/lang/string."<init>":(ljava/lang/string;)v

   18 : invokedynamic # 6 , 0     // invokedynamic #0:makeconcatwithconstants:(ljava/lang/string;ljava/lang/string;)ljava/lang/string;

   23 : astore_1

   24 : aload_1

   25 : invokevirtual # 7      // method java/lang/string.intern:()ljava/lang/string;

   28 : pop

   29 : ldc   # 8      // string tomcat

   31 : astore_2

   32 : getstatic  # 9      // field java/lang/system.out:ljava/io/printstream;

   35 : aload_1

   36 : aload_2

   37 : if_acmpne  44

   40 : iconst_1

   41 : goto    45

   44 : iconst_0

   45 : invokevirtual # 10      // method java/io/printstream.println:(z)v

   48 : return

   linenumbertable:

   line 11 : 0

   line 13 : 24

   line 14 : 29

   line 15 : 32

   line 16 : 48

   stackmaptable: number_of_entries = 2

   frame_type = 255 /* full_frame */

    offset_delta = 44

    locals = [ class "[ljava/lang/string;", class java/lang/string, class java/lang/string ]

    stack = [ class java/io/printstream ]

   frame_type = 255 /* full_frame */

    offset_delta = 0

    locals = [ class "[ljava/lang/string;" , class java/lang/string, class java/lang/string ]

    stack = [ class java/io/printstream, int ]

}

sourcefile: "stringnotexistinpoolbeforeintern.java"

innerclasses:

  public static final # 58 = # 57 of # 61 ; // lookup=class java/lang/invoke/methodhandles$lookup of class java/lang/invoke/methodhandles

bootstrapmethods:

  0 : # 30 ref_invokestatic java/lang/invoke/stringconcatfactory.makeconcatwithconstants:(ljava/lang/invoke/methodhandles$lookup;ljava/lang/string;ljava/lang/invoke/methodtype;ljava/lang/string;[ljava/lang/object;)ljava/lang/invoke/callsite;

  method arguments:

   # 31 \u0001\u0001

可以看到常量池有tom、cat、tomcat

小结

当调用intern方法时,如果常量池已经包含一个equals此string对象的字符串,则返回池中的字符串
当调用intern方法时,如果常量池没有一个equals此string对象的字符串,将此string对象添加到池中,并返回此string对象的引用(即intern方法返回指向heap中的此string对象引用)

所有literal strings及string-valued constant expressions都是interned的

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。

原文链接:https://segmentfault测试数据/a/1190000018775484

查看更多关于关于java String中intern的深入讲解的详细内容...

  阅读:11次