遇到这样一段代码,运行发现结果出现意外。
String str1 = "str";
String str2 = "ing";
String str3 = "str" + "ing";// @1
String str4 = "string";
System.out.println(str3 == str4);//true
String str5 = str1 + str2;// @2
System.out.println(str5 == str4);//false
代码虽然短,但是背后的知识点却是不少,涉及到常量池,运算符重载等相关知识点。
关于Java字符串拼接的知识可以参考:
http://droidyue.com/blog/2014/08/30/java-details-string-concatenation/
http://www.jianshu.com/p/88aa19fc21c6
使用java反编译命令javap -c Test可以看到编译优化后的代码
此处主要分析关键2处,@1和@2
@1处,此处的拼接是在java编译阶段实现,由java编译器实现。直接把str和ing拼凑形成一个新的字符串常量报存在常量池中。所以str3 == str4输出true很好理解。
@2处,输出为什么会为false呢。这也是自己刚开始不明白的,看了编译后的代码终于明白。
String str5 = str1 + str2对应编译后代码30行,创建了一个StringBuilder,至于为何会创建这个StringBuidler,和 + 这个符号有关系。在Java中,唯一被重载的运算符就是字符串的拼接相关的。+,+=(本来人家是用来做算术运算的)。除此之外,Java设计者不允许重载其他的运算符。@2中str1和str2的类型都是String类型,+连接起来的时候就会将str1和str2先转化为String类型在使用StringBuilder的append方法将两个字符串拼起来,所以35行,出现String.valueOf();
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
下面是StringBuidler的代码:
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
@Override
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
可以看到最后会new String(),这样new出来的String是不在常量池中的,所以System.out.println(str5 == str4);//false
以上只是自己的分析,如有错误,欢迎轻拍。