本文在本人2个博客https://blog.csdn.net/21aspnet和https://blog.csdn.net/unix21unix21同步发布
先上代码:
public class TestApp {
public static void main(String[] args) {
String s1 = "abc";
String s2 = new String("abc");
String s3 = new String("abc");
System.out.println(s2 == s1.intern());
System.out.println(s2 == s3.intern());
System.out.println(s1 == s3.intern());
System.out.println(s3 == s3.intern());
String s4 = "abcd";
String s5 = new String("abcde");
System.out.println(s4);
System.out.println(s5.intern());
}
}
输出:
false
false
true
false
abcd
abcde
第一个知识点--String.intern:
Returns a canonical representation for the string object. A pool of strings, initially empty, is maintained privately by the class String. When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned. It follows that for any two strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is true. All literal strings and string-valued constant expressions are interned. String literals are defined in section 3.10.5 of the The Java? Language Specification.
上面是jdk源码中对intern方法的详细解释。简单来说就是intern用来返回常量池中的某字符串,如果常量池中已经存在该字符串,则直接返回常量池中该对象的引用。否则,在常量池中加入该对象,然后返回引用。
生成class文件
Classfile /D:/TestApp.class
Last modified 2019-3-5; size 869 bytes
MD5 checksum 9093744ea00ada929804a84661bb3119
Compiled from "TestApp.java"
public class TestApp
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #12.#25 // java/lang/Object."<init>":()V
#2 = String #26 // abc
#3 = Class #27 // java/lang/String
#4 = Methodref #3.#28 // java/lang/String."<init>":(Ljava/lang/String;)V
#5 = Fieldref #29.#30 // java/lang/System.out:Ljava/io/PrintStream;
#6 = Methodref #3.#31 // java/lang/String.intern:()Ljava/lang/String;
#7 = Methodref #32.#33 // java/io/PrintStream.println:(Z)V
#8 = String #34 // abcd
#9 = String #35 // abcde
#10 = Methodref #32.#36 // java/io/PrintStream.println:(Ljava/lang/String;)V
#11 = Class #37 // TestApp
#12 = Class #38 // 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 #39 // "[Ljava/lang/String;"
#21 = Class #27 // java/lang/String
#22 = Class #40 // java/io/PrintStream
#23 = Utf8 SourceFile
#24 = Utf8 TestApp.java
#25 = NameAndType #13:#14 // "<init>":()V
#26 = Utf8 abc
#27 = Utf8 java/lang/String
#28 = NameAndType #13:#41 // "<init>":(Ljava/lang/String;)V
#29 = Class #42 // java/lang/System
#30 = NameAndType #43:#44 // out:Ljava/io/PrintStream;
#31 = NameAndType #45:#46 // intern:()Ljava/lang/String;
#32 = Class #40 // java/io/PrintStream
#33 = NameAndType #47:#48 // println:(Z)V
#34 = Utf8 abcd
#35 = Utf8 abcde
#36 = NameAndType #47:#41 // println:(Ljava/lang/String;)V
#37 = Utf8 TestApp
#38 = Utf8 java/lang/Object
#39 = Utf8 [Ljava/lang/String;
#40 = Utf8 java/io/PrintStream
#41 = Utf8 (Ljava/lang/String;)V
#42 = Utf8 java/lang/System
#43 = Utf8 out
#44 = Utf8 Ljava/io/PrintStream;
#45 = Utf8 intern
#46 = Utf8 ()Ljava/lang/String;
#47 = Utf8 println
#48 = Utf8 (Z)V
{
public TestApp();
descriptor: ()V
flags: 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 1: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=6, args_size=1
0: ldc #2 // String abc ///加载常量池中的第2项("abc")到栈中
2: astore_1 ///将0:中的引用赋值给第1个局部变量,即s1 = "abc"
3: new #3 // class java/lang/String ///生成String实例
6: dup ///复制3:生成对象也就是s2的引用并压入栈中
7: ldc #2 // String abc ///加载常量池中的第2项("abc")到栈中
9: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V ///调用常量池中的第4项,即java/lang/String."<init>"方法。
12: astore_2 ///将9:中的引用赋值给第2个局部变量,即s2 = new String("abc");
13: new #3 // class java/lang/String ///生成String实例
16: dup ///复制13:生成对象的引用并压入栈中
17: ldc #2 // String abc ///加载常量池中的第2项("abc")到栈中
19: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V ///调用常量池中的第4项,即java/lang/String."<init>"方法。
22: astore_3 ///将19:中的引用赋值给第3个局部变量,即s3 = new String("abc");
23: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; ///获取指定类的静态域,并将其值压入栈顶
26: aload_2 ///把第2个本地变量也就是s2送到栈顶
27: aload_1 ///把第1个本地变量也就是s1送到栈顶
28: invokevirtual #6 // Method java/lang/String.intern:()Ljava/lang/String; ///对s1调用String.intern方法返回的是常连池对象的引用#2
31: if_acmpne 38 ///比较栈顶两引用型数值,当结果不相等时跳转 比较s2 == s1.intern() 6:和#2显然不等
34: iconst_1 ///int型常量值1进栈 也就是true
35: goto 39 ///跳转到39:
38: iconst_0 ///int型常量值0进栈 也就是false
39: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
42: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
45: aload_2 ///把第2个本地变量也就是s2送到栈顶
46: aload_3 ///把第3个本地变量也就是s3送到栈顶
47: invokevirtual #6 // Method java/lang/String.intern:()Ljava/lang/String; ///s3调用String.intern方法返回的是常连池对象的引用#2
50: if_acmpne 57 ///也就是比较s2 == s3.intern() 6:和#2显然不等
53: iconst_1
54: goto 58
57: iconst_0
58: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
61: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
64: aload_1 ///把第1个本地变量也就是s1送到栈顶
65: aload_3 ///把第3个本地变量也就是s3送到栈顶
66: invokevirtual #6 // Method java/lang/String.intern:()Ljava/lang/String; //对s3调用String.intern方法返回的是常连池对象的引用#2
69: if_acmpne 76 ///也就是比较s1 == s3.intern() #2和#2显然相等
72: iconst_1
73: goto 77
76: iconst_0
77: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
80: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
83: aload_3
84: aload_3
85: invokevirtual #6 // Method java/lang/String.intern:()Ljava/lang/String;
88: if_acmpne 95 ///也就是比较s3 == s3.intern() 13:和#2显然不等
91: iconst_1
92: goto 96
95: iconst_0
96: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
99: ldc #8 // String abcd
101: astore 4
103: new #3 // class java/lang/String
106: dup
107: ldc #9 // String abcde
109: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V
112: astore 5
114: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
117: aload 4
119: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
122: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
125: aload 5
127: invokevirtual #6 // Method java/lang/String.intern:()Ljava/lang/String;
130: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
133: return
LineNumberTable:
line 5: 0
line 6: 3
line 7: 13
line 9: 23
line 10: 42
line 11: 61
line 12: 80
line 14: 99
line 15: 103
line 16: 114
line 17: 122
line 18: 133
StackMapTable: number_of_entries = 8
frame_type = 255 /* full_frame */
offset_delta = 38
locals = [ class "[Ljava/lang/String;", class java/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, class java/lang/String ]
stack = [ class java/io/PrintStream, int ]
frame_type = 81 /* same_locals_1_stack_item */
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, class java/lang/String ]
stack = [ class java/io/PrintStream, int ]
frame_type = 81 /* same_locals_1_stack_item */
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, class java/lang/String ]
stack = [ class java/io/PrintStream, int ]
frame_type = 81 /* same_locals_1_stack_item */
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, class java/lang/String ]
stack = [ class java/io/PrintStream, int ]
}
SourceFile: "TestApp.java"
///是我加的注释。可以参考:《通过反编译深入理解Java String及intern》
JVM指令可以自行搜索。
关键就是这句:s1 == s3.intern()
s1就是常量池的地址 也就是#2
而s3.intern()直接去找#2
#2==#2
所以是true!
比较s2 == s1.intern() 6:和#2显然不等 6:就是栈上的地址 自然和 常量池地址#2不等啊
总结这样就行: 1.8下
1. new字符串是会进常量池
2.相等的字符串常量池自然相等
3.常量池和栈地址自然不等