1、下面程序输出结果:
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都会在常量池中创建对象,s3是变量s1和常量"c"拼接而来,通过javap命令 可以看到具体实现步骤.
//编译要生成所有调试信息
javac -g Demo.java
//反编译
javap -v Demo
使用javap命令结果如下:
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命令:把常量池中的项压入栈
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,跳转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是通过创建StringBuilder对象.append()方法进行连接,然后调用toString()再赋值给s3变量,此时字符串"abc"对象在堆内存中,故判断s1 == s3为false.
一些概念解释:
常量池:
在编译器被确定,并保存在已编译的.class字节码文件中的一些数据,它包括关于类,方法,接口中的常量.也包括字符串直接量.
直接量:
指在程序中通过源代码直接给出的值.如:
String s1 = "hello";
String s2 = "he" + "llo";
s1 == s2 //true
原因:"he"和"llo"都是字符串常量,当一个字符串由多个字符串常量连接而成时,他本身也就是字符串常量,s2同样在编译期就被解析为一个字符串常量,故为true.
网友评论