当前位置: 移动技术网 > IT编程>开发语言>Java > 关于java String中intern的深入讲解

关于java String中intern的深入讲解

2019年07月19日  | 移动技术网IT编程  | 我要评论


本文主要研究一下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.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的

总结

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网