首页 > 编程 > Java > 正文

关于java String中intern的深入讲解

2019-11-26 09:07:17
字体:
来源:转载
供稿:网友


本文主要研究一下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™ 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.javajavap -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: 1Constant 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.javajavap -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: 3Constant 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/MethodHandlesBootstrapMethods: 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的

总结

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

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表