先来一个引子,来打开这个话题吧
public static void main(String[] args) {
String s1 = "hello world";
String s2 = new String("hello world");
String s3 = new String("hello world").intern();
String s4 = new String("hello world");
String s5 = "hello world";
System.out.println(s1==s5);
System.out.println(s1==s2);
System.out.println(s1==s3);
System.out.println(s2==s4);
System.out.println(s2==s3);
}
如果你能毫不犹豫的说上面代码运行的结果,说明你对String有一定的了解了。你也能通过String相关问题的面试了,但你能说出为什么,你对 ==的机制就更了解。哈哈,不多费话了,直接上运行的结果吧,以此来打开我讨论的话题。
Disconnected from the target VM, address: '127.0.0.1:50688', transport: 'socket'
true
false
true
false
false
先来解释下原因,
- s1==s5,是因为s1,s5的指针都指向了常量池中 hello world.
- s1==s2 为false,虽然在编译期间,字面量s1,s2都指向了常量池中的hello world,但在运行期间,但s2在运行期间又被new String load成了一个对象,该对象批向了常量池中 hello world的地址,所以会为false
- s1==s3 按上面所说,这个应该是false,但又为什么会是true呢?我们可以看下inner()方法的实现
public native String intern();加了native进行修饰,说明是native变量,说明该方法会常量池中是的引用,所以是true
- s2==s4,s2==s4比较容易理解,是两个不同对象的,==肯定为false
为了更好的理解上面说的问题,让我们来看class的内容,javap以的内容如下
/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home\bin\javap -c -l -s -verbose com.hongshu.gold.biz.base.TestString
Classfile /Users/hongshu/work/IdeaProjects/oschina/gold-trade/biz/target/classes/com/hongshu/gold/biz/base/TestString.class
Last modified Sep 7, 2018; size 1135 bytes
MD5 checksum a75719013829a0e0ed0efe8695d5751f
Compiled from "TestString.java"
public class com.hongshu.gold.biz.base.TestString
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #9.#33 // java/lang/Object."<init>":()V
#2 = String #34 // hello world
#3 = Class #35 // java/lang/String
#4 = Methodref #3.#36 // java/lang/String."<init>":(Ljava/lang/String;)V
#5 = Methodref #3.#37 // java/lang/String.intern:()Ljava/lang/String;
#6 = Fieldref #38.#39 // java/lang/System.out:Ljava/io/PrintStream;
#7 = Methodref #40.#41 // java/io/PrintStream.println:(Z)V
#8 = Class #42 // com/hongshu/gold/biz/base/TestString
#9 = Class #43 // java/lang/Object
#10 = Utf8 <init>
#11 = Utf8 ()V
#12 = Utf8 Code
#13 = Utf8 LineNumberTable
#14 = Utf8 LocalVariableTable
#15 = Utf8 this
#16 = Utf8 Lcom/hongshu/gold/biz/base/TestString;
#17 = Utf8 main
#18 = Utf8 ([Ljava/lang/String;)V
#19 = Utf8 args
#20 = Utf8 [Ljava/lang/String;
#21 = Utf8 s1
#22 = Utf8 Ljava/lang/String;
#23 = Utf8 s2
#24 = Utf8 s3
#25 = Utf8 s4
#26 = Utf8 s5
#27 = Utf8 StackMapTable
#28 = Class #20 // "[Ljava/lang/String;"
#29 = Class #35 // java/lang/String
#30 = Class #44 // java/io/PrintStream
#31 = Utf8 SourceFile
#32 = Utf8 TestString.java
#33 = NameAndType #10:#11 // "<init>":()V
#34 = Utf8 hello world
#35 = Utf8 java/lang/String
#36 = NameAndType #10:#45 // "<init>":(Ljava/lang/String;)V
#37 = NameAndType #46:#47 // intern:()Ljava/lang/String;
#38 = Class #48 // java/lang/System
#39 = NameAndType #49:#50 // out:Ljava/io/PrintStream;
#40 = Class #44 // java/io/PrintStream
#41 = NameAndType #51:#52 // println:(Z)V
#42 = Utf8 com/hongshu/gold/biz/base/TestString
#43 = Utf8 java/lang/Object
#44 = Utf8 java/io/PrintStream
#45 = Utf8 (Ljava/lang/String;)V
#46 = Utf8 intern
#47 = Utf8 ()Ljava/lang/String;
#48 = Utf8 java/lang/System
#49 = Utf8 out
#50 = Utf8 Ljava/io/PrintStream;
#51 = Utf8 println
#52 = Utf8 (Z)V
{
public com.hongshu.gold.biz.base.TestString();
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 8: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/hongshu/gold/biz/base/TestString;
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 hello world
2: astore_1
3: new #3 // class java/lang/String
6: dup
7: ldc #2 // String hello world
9: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V
12: astore_2
13: new #3 // class java/lang/String
16: dup
17: ldc #2 // String hello world
19: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V
22: invokevirtual #5 // Method java/lang/String.intern:()Ljava/lang/String;
25: astore_3
26: new #3 // class java/lang/String
29: dup
30: ldc #2 // String hello world
32: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V
35: astore 4
37: ldc #2 // String hello world
39: astore 5
41: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
44: aload_1
45: aload 5
47: if_acmpne 54
50: iconst_1
51: goto 55
54: iconst_0
55: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
58: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
61: aload_1
62: aload_2
63: if_acmpne 70
66: iconst_1
67: goto 71
70: iconst_0
71: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
74: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
77: aload_1
78: aload_3
79: if_acmpne 86
82: iconst_1
83: goto 87
86: iconst_0
87: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
90: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
93: aload_2
94: aload 4
96: if_acmpne 103
99: iconst_1
100: goto 104
103: iconst_0
104: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
107: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
110: aload_2
111: aload_3
112: if_acmpne 119
115: iconst_1
116: goto 120
119: iconst_0
120: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
123: return
LineNumberTable:
line 13: 0
line 14: 3
line 15: 13
line 16: 26
line 17: 37
line 20: 41
line 21: 58
line 22: 74
line 25: 90
line 26: 107
line 29: 123
LocalVariableTable:
Start Length Slot Name Signature
0 124 0 args [Ljava/lang/String;
3 121 1 s1 Ljava/lang/String;
13 111 2 s2 Ljava/lang/String;
26 98 3 s3 Ljava/lang/String;
37 87 4 s4 Ljava/lang/String;
41 83 5 s5 Ljava/lang/String;
StackMapTable: number_of_entries = 10
frame_type = 255 /* full_frame */
offset_delta = 54
locals = [ class "[Ljava/lang/String;", class java/lang/String, class java/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, class java/lang/String, class java/lang/String ]
stack = [ class java/io/PrintStream, int ]
frame_type = 78 /* 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, class java/lang/String, class java/lang/String ]
stack = [ class java/io/PrintStream, int ]
frame_type = 78 /* 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, class java/lang/String, class java/lang/String ]
stack = [ class java/io/PrintStream, int ]
frame_type = 79 /* 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, class java/lang/String, class java/lang/String ]
stack = [ class java/io/PrintStream, int ]
frame_type = 78 /* 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, class java/lang/String, class java/lang/String ]
stack = [ class java/io/PrintStream, int ]
}
SourceFile: "TestString.java"
Process finished with exit code 0
常量池中字面量引用只有一个 helloworld的引用 这说明,虽然声明多个变量,String为了提高其性,在编译时,只在常量池中生一个引用。
未完待续