关于java String中intern的深入讲解
作者:codecraft
这篇文章主要给大家介绍了关于java String中intern的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用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的
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。