sequence

This article focuses on the 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 inSection 3.10.5 of the * <cite> the Java&trade; Language Specification</cite>. * * @returna 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 String Intern ();  / /... }Copy the code
  • When you call intern, if the constant pool already contains an equals String, return the String from the pool
  • When you call intern, if the constant pool does not have an equals String, add the String to the pool and return a reference to the String.That is, the intern method returns a reference to the String in the heap)
  • All Literal strings and String-Valued expressions are interned

The instance

Based on the jdk12

StringExistInPoolBeforeIntern

public class StringExistInPoolBeforeIntern {

    public static void main(String[] args){
        String stringObject = new String("tomcat"); //NOTE before intern, string table already had tomcat, so intern returns tomcat, does not point to stringObject stringObject. Intern (); String stringLiteral ="tomcat";
        System.out.println(stringObject == stringLiteral); //false}}Copy the code
  • Tomcat is a literal string from interned. The constant pool does not have Tomcat, so we added it to the constant pool, which has tomcat. Also, since stringObject is new, there is also a Tomcat in the heap that points to tomcat in the heap
  • Stringobject.intern () returns tomcat for the constant pool in the heap; StringLiteral is tomcat, the literal string, and since the constant pool already has that value, stringLiteral points to Tomcat for the constant pool in the heap
  • StringObject refers to Tomcat in the heap, and stringLiteral refers to Tomcat in the constant pool in the heap, so the difference is false

StringNotExistInPoolBeforeIntern

public class StringNotExistInPoolBeforeIntern {

    public static void main(String[] args){
        String stringObject = new String("tom") + new String("cat"); //NOTE before intern, string table has no Tomcat, so intern points to stringObject stringObject. Intern (); String stringLiteral ="tomcat";
        System.out.println(stringObject == stringLiteral); //true}}Copy the code
  • Literal strings Tom and cat are literal strings from interned. Literal strings Tom and cat are literal strings from interned. Also, since stringObject is new and concat both Tom and CAT, there is a Tomcat in the heap
  • When the stringObject intern method executes, it is added to the constant pool because tomcat is not in the constant pool, and intern() returns a reference to Tomcat in the heap; StringLiteral is the literal string tomcat, since stringobject.Intern () has added Tomcat to the constant pool and points to a reference to Tomcat in the heap, So stringLiteral returns a reference to Tomcat in the heap
  • Since stringLiteral returns a reference to Tomcat in the heap, which is stringObject, the two are equal and return true

javap

Based on the jdk12

StringExistInPoolBeforeIntern

javac src/main/java/com/example/javac/StringExistInPoolBeforeIntern.java javap -v SRC/main/Java/com/example/javac/StringExistInPoolBeforeIntern class Last modified on April 6, 2019; 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."
      
       ":()V
      
   #2 = Class #22 // java/lang/String
   #3 = String #23 // tomcat
   #4 = Methodref #2.#24 // java/lang/String."
      
       ":(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 
      
  #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 // "
      
       ":()V
      
  #22 = Utf8 java/lang/String
  #23 = Utf8 tomcat
  #24 = NameAndType #10:#33 // "
      
       ":(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."
      
       ":()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."
      
       ":(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"
Copy the code
  • You can see that the constant pool has tomcat

StringNotExistInPoolBeforeIntern

javac src/main/java/com/example/javac/StringNotExistInPoolBeforeIntern.java javap -v SRC/main/Java/com/example/javac/StringNotExistInPoolBeforeIntern class Last modified on April 6, 2019; 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."
      
       ":()V
      
   #2 = Class #25 // java/lang/String
   #3 = String #26 // tom
   #4 = Methodref #2.#27 // java/lang/String."
      
       ":(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 
      
  #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 // "
      
       ":()V
      
  #25 = Utf8 java/lang/String
  #26 = Utf8 tom
  #27 = NameAndType #13:#42 // "
      
       ":(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."
      
       ":()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."
      
       ":(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."
      
       ":(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
Copy the code
  • You can see the constant pool has Tom, cat, and tomcat

summary

  • When you call intern, if the constant pool already contains an equals String, return the String from the pool
  • When you call intern, if the constant pool does not have an equals String, add the String to the pool and return a reference to the String.That is, the intern method returns a reference to the String in the heap)
  • All Literal strings and String-Valued expressions are interned

doc

  • Talk about the String Intern
  • Why does String.intern() return different results under JDK8 and JDK9?
  • How to Initialize and Compare Strings in Java?
  • Difference between String literal and New String object in Java
  • Talk about PermGen and Metaspace for the JVM
  • Guide to Java String Pool
  • String Literal Vs String Object in Java