In depth explanation of intern in java String
- 2021-07-13 05:24:04
- OfStack
Sequence
In this paper, we mainly study the intern of java String under 1
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();
//......
}
When the intern method is called, if the constant pool already contains a string for the equals String object, the string in the pool is returned
When the intern method is called, if the constant pool does not have a string for the equals String object, add the String object to the pool and return a reference to the String object (that is, the intern method returns a reference to the String object in heap)
All literal strings and string-valued constant expressions are interned
Instances
Based on jdk12
StringExistInPoolBeforeIntern
public class StringExistInPoolBeforeIntern {
public static void main(String[] args){
String stringObject = new String("tomcat");
//NOTE In intern Before, string table Already have tomcat , therefore intern Return tomcat , does not point to stringObject
stringObject.intern();
String stringLiteral = "tomcat";
System.out.println(stringObject == stringLiteral); //false
}
}
tomcat This literal string is interned, and the constant pool does not have tomcat, so it is added to the constant pool, which has an tomcat;; In addition, since stringObject is new, there is also an tomcat in heap, and at this time it points to tomcat in heap
stringObject. intern () returns the tomcat of the constant pool in heap; stringLiteral is tomcat, literal, string. Since the constant pool already has this value, stringLiteral points to tomcat of the constant pool in heap
At this time, stringObject points to tomcat in heap, while stringLiteral is tomcat of constant pool in heap, so the two are different and return false
StringNotExistInPoolBeforeIntern
public class StringNotExistInPoolBeforeIntern {
public static void main(String[] args){
String stringObject = new String("tom") + new String("cat");
//NOTE In intern Before, string table No tomcat , therefore intern Point stringObject
stringObject.intern();
String stringLiteral = "tomcat";
System.out.println(stringObject == stringLiteral); //true
}
}
tom and cat, two literal string, are interned, and the constant pool does not have tom and cat, so it is added to the constant pool, which includes tom and cat; In addition, because stringObject comes from new and is concat of tom and cat2, there is one tomcat in heap
When the intern method of stringObject is executed, tomcat is added to the constant pool because there is no tomcat in the constant pool, and intern () returns a reference to tomcat in heap; stringLiteral is tomcat, literal string. Since stringObject. intern () has added tomcat to the constant pool and points to a reference to tomcat in heap, stringLiteral returns a reference to tomcat in heap
Since stringLiteral returns a reference to tomcat in heap, which is actually stringObject, the two are equal and return true
javap
Based on jdk12
StringExistInPoolBeforeIntern
javac src/main/java/com/example/javac/StringExistInPoolBeforeIntern.java
javap -v src/main/java/com/example/javac/StringExistInPoolBeforeIntern.class
Last modified 2019 Year 4 Month 6 Day ; 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"
You can see that the constant pool has an tomcat
StringNotExistInPoolBeforeIntern
javac src/main/java/com/example/javac/StringNotExistInPoolBeforeIntern.java
javap -v src/main/java/com/example/javac/StringNotExistInPoolBeforeIntern.class
Last modified 2019 Year 4 Month 6 Day ; 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
You can see that the constant pools are tom, cat and tomcat
Summary
When the intern method is called, if the constant pool already contains 1 equals string for this String object, the string in the pool is returned
When the intern method is called, if the constant pool does not have a string for the equals String object, add the String object to the pool and return a reference to the String object (that is, the intern method returns a reference to the String object in heap)
All literal strings and string-valued constant expressions are interned
Summarize