字符串比较
现有以下代码,需要分析其结果
String s0 = "red";
String s1 = "re";
String s2 = "d";
String s3 = s1 + s2;
System.out.println(s0 == ("re" + "d"));//1
System.out.println(s0 == s3);//2
结果如下:
true
false
为什么会这样呢?接下来我们一一分析
-
对于 s0 == (“re” + “d”) 来说,由于"re" "d" 都是字符串常量,所以在Java编译时就会进行自动优化,将其合并为**“red”**
-
方式1:我们将代码编译后生成的.class文件打开,就可以发现
之前的
System.out.println(s0 == ("re" + "d"));
已经被优化为
System.out.println(s0 == "red");
-
方式2: 也可以使用反汇编来查看详细过程
public static void main(java.lang.String[]); Code: 0: ldc #2 // String red 2: astore_1 3: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 6: aload_1 7: ldc #2 // String red 9: if_acmpne 16 12: iconst_1 13: goto 17 16: iconst_0 17: invokevirtual #4 // Method java/io/PrintStream.println:(Z)V 20: return }
我们可以发现,在编译时第7行时就将字符串常量拼接成了 red。
-
因此,最后由于使用 == 比较**(地址比较)**,且比较的是同一个字符串 red ,其在字符串常量池中只会存储了一份,所以一定是同一个,结果为true。
-
对于 s0 == s3
public static void main(java.lang.String[]); Code: 0: ldc #2 // String red 2: astore_1 3: ldc #3 // String re 5: astore_2 6: ldc #4 // String d 8: astore_3 9: new #5 // class java/lang/StringBuilder 12: dup 13: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V 16: aload_2 17: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 20: aload_3 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 29: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream; 32: aload_1 33: aload 4 35: if_acmpne 42 38: iconst_1 39: goto 43 42: iconst_0 43: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V 46: return }
通过反汇编我们可以发现,其s3=s1+s2在拼接时,底层调用了StringBuilder.append()方法,最终又调用toString()转为字符串对象,内存布局如下,所以s3中保存的是StringBuilder对象的地址,所以s0==s3结果为false.