题目一:
String s1 = "a";
String s2 = "b";
String s3 = "ab";
String s4 = s1 + s2;
System.out.println(s3 == s4);
答案:false
首先贴出反编译后的常量池:
Constant pool:
#1 = Methodref #12.#40 // java/lang/Object."<init>":()V
#2 = String #41 // a
#3 = String #42 // b
#4 = String #43 // ab
#5 = Class #44 // java/lang/StringBuilder
#6 = Methodref #5.#40 // java/lang/StringBuilder."<init>":()V
#7 = Methodref #5.#45 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#8 = Methodref #5.#46 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#9 = Fieldref #47.#48 // java/lang/System.out:Ljava/io/PrintStream;
#10 = Methodref #49.#50 // java/io/PrintStream.println:(Z)V
#11 = Class #51 // DeadLockDemo
#12 = Class #52 // java/lang/Object
#13 = Utf8 <init>
#14 = Utf8 ()V
#15 = Utf8 Code
#16 = Utf8 LineNumberTable
#17 = Utf8 LocalVariableTable
#18 = Utf8 this
#19 = Utf8 LDeadLockDemo;
#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 s4
#29 = Utf8 StackMapTable
#30 = Class #23 // "[Ljava/lang/String;"
#31 = Class #53 // java/lang/String
#32 = Class #54 // java/io/PrintStream
#33 = Utf8 Exceptions
#34 = Class #55 // java/util/concurrent/ExecutionException
#35 = Class #56 // java/lang/InterruptedException
#36 = Utf8 SourceFile
#37 = Utf8 DeadLockDemo.java
#38 = Utf8 RuntimeVisibleAnnotations
#39 = Utf8 Ljdk/nashorn/internal/runtime/logging/Logger;
#40 = NameAndType #13:#14 // "<init>":()V
#41 = Utf8 a
#42 = Utf8 b
#43 = Utf8 ab
#44 = Utf8 java/lang/StringBuilder
#45 = NameAndType #57:#58 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#46 = NameAndType #59:#60 // toString:()Ljava/lang/String;
#47 = Class #61 // java/lang/System
#48 = NameAndType #62:#63 // out:Ljava/io/PrintStream;
#49 = Class #54 // java/io/PrintStream
#50 = NameAndType #64:#65 // println:(Z)V
#51 = Utf8 DeadLockDemo
#52 = Utf8 java/lang/Object
#53 = Utf8 java/lang/String
#54 = Utf8 java/io/PrintStream
#55 = Utf8 java/util/concurrent/ExecutionException
#56 = Utf8 java/lang/InterruptedException
#57 = Utf8 append
#58 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#59 = Utf8 toString
#60 = Utf8 ()Ljava/lang/String;
#61 = Utf8 java/lang/System
#62 = Utf8 out
#63 = Utf8 Ljava/io/PrintStream;
#64 = Utf8 println
#65 = Utf8 (Z)V
看看具体的汇编代码:
String s1 = "a";
// 0: ldc #2 // String a
// 2: astore_1
String s2 ="b" ;
// 3: ldc #3 // String b
// 5: astore_2
String s3 = "ab";
// 6: ldc #4 // String ab
// 8: astore_3
String s4 = s1+s2;
// 9: new #5 // class java/lang/StringBuilder
// 12: dup
// 13: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V
// 16: aload_1
// 17: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
// 20: aload_2
// 21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
// 24: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
// 27: astore 4
System.out.println(s3==s4);
从上图来看,当类在编译的时候,会创建出一个常量池,然后执行jvm指令的时候就会根据常量池去查找所需要的东西
当执行下边着几行代码时,都是通过常量池找到这几个常量,然后放入将这几个符号变成字符串对象,最后将字符串对象放入StringTable(串池)中
但是在执行下面这行代码的时候是完全不同的
如下图所示
- 先执行的是一个new,创建了一个StringBuilder对象
- 然后invokespecial 调用了StringBuilder的空参构造方法
- 接着aload_1 读取本地变量1的值,也就是a的值
- 接着invokevirtual调用了append方法,将a的值作为参数
- 继续aload_2读取本地变量2的值,也就是b的值
- 然后invokevirtual调用了append方法,将b的值作为参数
- 又继续invokevirtual调用了toString的方法,走进源码看Stringbuilder中的toString方法
又创建了一个String对象,
然后执行astore 将结果放到本地变量4号位值中
至此就完成了
这几行代码的执行
在最后比较的时候判断s3==s4,由此看来是错误的。s3指向的是StringTable中的字符串对象,而s4指向的是堆中的对象,两个的地址是不相同的,所以false
题目二:
String s1 = "a";
String s2 = "b";
String s3 = "ab";
String s4 ="a"+"b";
System.out.println(s3 == s4);
答案:ture
看看具体的汇编代码:
String s1 = "a";
// 0: ldc #2 // String a
// 2: astore_1
String s2 ="b" ;
// 3: ldc #3 // String b
// 5: astore_2
String s3 = "ab";
// 6: ldc #4 // String ab
// 8: astore_3
String s4 = "a"+"b";
// 9: ldc #4 // String ab
// 11: astore 4
不难看出,在执行String s4=“a"+"b";的时候,会先直接找常量池的#4,与执行String s3=”ab“的过程是一样的,因为javac在编译期间就做了优化,”a“+”b“的结果已经是”ab“了
所以结果是ture,都是指向StringTable中的”ab“