欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

关于java String中intern的深入讲解

程序员文章站 2024-02-22 19:02:12
序 本文主要研究一下java string的intern string.intern() java.base/java/lang/string.java...


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

总结

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