软件编程
位置:首页>> 软件编程>> java编程>> 关于java String中intern的深入讲解

关于java String中intern的深入讲解

作者:codecraft  发布时间:2023-01-24 18:18:36 

标签:java,string,intern


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

String.intern()

java.base/java/lang/String.java


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&trade; 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


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


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


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


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.com/a/1190000018775484

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com