前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >聊聊java String的intern

聊聊java String的intern

原创
作者头像
code4it
发布2019-04-06 11:59:08
5000
发布2019-04-06 11:59:08
举报
文章被收录于专栏:码匠的流水账

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

String.intern()

java.base/java/lang/String.java

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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的

doc

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • String.intern()
  • 实例
    • StringExistInPoolBeforeIntern
      • StringNotExistInPoolBeforeIntern
      • javap
        • StringExistInPoolBeforeIntern
          • StringNotExistInPoolBeforeIntern
          • 小结
          • doc
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档