1募寨、下面程序輸出結(jié)果:
public class Demo{
public static void main(String[] args) throws Exception {
String s1 = "ab";
String s2 = "abc";
String s3 = s1 + "c";
System.out.println(s3==s2);//true
}
}
分析:s1 s2都會(huì)在常量池中創(chuàng)建對(duì)象,s3是變量s1和常量"c"拼接而來,通過javap命令 可以看到具體實(shí)現(xiàn)步驟.
//編譯要生成所有調(diào)試信息
javac -g Demo.java
//反編譯
javap -v Demo
使用javap命令結(jié)果如下:
Classfile /C:/Users/Desktop/Demo.class
Last modified 2018-3-27; size 907 bytes
MD5 checksum d10a17ec64e71338de935811f6abbb35
Compiled from "Demo.java"
public class Demo
SourceFile: "Demo.java"
minor version: 0
major version: 51
flags: ACC_PUBLIC, ACC_SUPER
Constant pool://常量池
#1 = Methodref #12.#36 // java/lang/Object."<init>":()V
#2 = String #37 // ab
#3 = String #38 // abc
#4 = Class #39 // java/lang/StringBuilder
#5 = Methodref #4.#36 // java/lang/StringBuilder."<init>":()V
#6 = Methodref #4.#40 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#7 = String #41 // c
#8 = Methodref #4.#42 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#9 = Fieldref #43.#44 // java/lang/System.out:Ljava/io/PrintStream;
#10 = Methodref #45.#46 // java/io/PrintStream.println:(Z)V
#11 = Class #47 // Demo
#12 = Class #48 // java/lang/Object
#13 = Utf8 <init>
#14 = Utf8 ()V
#15 = Utf8 Code
#16 = Utf8 LineNumberTable
#17 = Utf8 LocalVariableTable
#18 = Utf8 this
#19 = Utf8 LDemo;
#20 = Utf8 main
#21 = Utf8 ([Ljava/lang/String;)V
#22 = Utf8 args
#23 = Utf8 [Ljava/lang/String;
#24 = Utf8 s1
#25 = Utf8 Ljava/lang/String;
#26 = Utf8 s2
#27 = Utf8 s3
#28 = Utf8 StackMapTable
#29 = Class #23 // "[Ljava/lang/String;"
#30 = Class #49 // java/lang/String
#31 = Class #50 // java/io/PrintStream
#32 = Utf8 Exceptions
#33 = Class #51 // java/lang/Exception
#34 = Utf8 SourceFile
#35 = Utf8 Demo.java
#36 = NameAndType #13:#14 // "<init>":()V
#37 = Utf8 ab
#38 = Utf8 abc
#39 = Utf8 java/lang/StringBuilder
#40 = NameAndType #52:#53 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#41 = Utf8 c
#42 = NameAndType #54:#55 // toString:()Ljava/lang/String;
#43 = Class #56 // java/lang/System
#44 = NameAndType #57:#58 // out:Ljava/io/PrintStream;
#45 = Class #50 // java/io/PrintStream
#46 = NameAndType #59:#60 // println:(Z)V
#47 = Utf8 Demo
#48 = Utf8 java/lang/Object
#49 = Utf8 java/lang/String
#50 = Utf8 java/io/PrintStream
#51 = Utf8 java/lang/Exception
#52 = Utf8 append
#53 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#54 = Utf8 toString
#55 = Utf8 ()Ljava/lang/String;
#56 = Utf8 java/lang/System
#57 = Utf8 out
#58 = Utf8 Ljava/io/PrintStream;
#59 = Utf8 println
#60 = Utf8 (Z)V
{
public Demo();
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
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LDemo;
public static void main(java.lang.String[]) throws java.lang.Exception;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=4, args_size=1
//ldc命令:把常量池中的項(xiàng)壓入棧
0: ldc #2 // String ab
2: astore_1
3: ldc #3 // String abc
5: astore_2
6: new #4 // class java/lang/StringBuilder
9: dup
10: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
13: aload_1
14: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: ldc #7 // String c
19: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
25: astore_3
26: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
29: aload_3
30: aload_2
31: if_acmpne 38 //如果判斷為true,跳轉(zhuǎn)38行
34: iconst_1 //也就是false
35: goto 39
38: iconst_0
39: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V
42: return
LineNumberTable:
line 3: 0
line 4: 3
line 5: 6
line 6: 26
line 7: 42
LocalVariableTable:
Start Length Slot Name Signature
0 43 0 args [Ljava/lang/String;
3 40 1 s1 Ljava/lang/String;
6 37 2 s2 Ljava/lang/String;
26 17 3 s3 Ljava/lang/String;
StackMapTable: number_of_entries = 2
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 ]
Exceptions:
throws java.lang.Exception
}
在main方法下面可以看出,String s1 = "ab",底層就是把"ab"字符串從常量池中拿出來賦給s1變量,而s3是通過創(chuàng)建StringBuilder對(duì)象.append()方法進(jìn)行連接,然后調(diào)用toString()再賦值給s3變量,此時(shí)字符串"abc"對(duì)象在堆內(nèi)存中,故判斷s1 == s3為false.
一些概念解釋:
常量池:
在編譯器被確定,并保存在已編譯的.class字節(jié)碼文件中的一些數(shù)據(jù),它包括關(guān)于類,方法,接口中的常量.也包括字符串直接量.
直接量:
指在程序中通過源代碼直接給出的值.如:
String s1 = "hello";
String s2 = "he" + "llo";
s1 == s2 //true
原因:"he"和"llo"都是字符串常量,當(dāng)一個(gè)字符串由多個(gè)字符串常量連接而成時(shí),他本身也就是字符串常量,s2同樣在編譯期就被解析為一個(gè)字符串常量,故為true.