一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情。
字符串拼接
一、常量与常量拼接的结果是在字符串常量池中的,原因就是在编译器会将常量与常量拼接优化成一个常量,如下代码所示:
可以看出来编译完的自己码文件已经将这部分代码优化了,上一章说过这种直接用引号生成的字符串是存在字符串常量池中的,所以拼接后的字符串实际上是直接存到常量池中的。由此衍生的面试题如下所示,由于编译期优化,而常量池中同一字符串子存在一份,所以变量a和b地址指向同一个字符串常量。
String a = "aaa" + "bbb";
String b = "aaabbb";
System.out.println(a == b); //true
二、字符串拼接中只要其中有一个是变量则结果就在堆中的非字符串常量池里。由此衍生出来的面试题如下,由于变量abc是存在堆中非常量池中的,而abc2是存在常量池中的,所以两个变量指向的不是同一个字符串,所以两个变量存的地址不同。
String a = new String("a");
String abc = a + "bc";
String abc2 = "abc";
System.out.println(abc == abc2); //false
intern相关面试题
intern()方法会查询字符串常量池中是否有和当前字符串变量相同值的字符串,如果有则返回字符串常量池中的变量地址,如果没有则将当前字符串的值放到常量池中并返回地址。由此衍生的面试题如下所示,由于abc指向的是堆中非常量池的字符串地址,而abc2指向的是常量池中的地址,所以abc != abc2,由于当前常量池已经存在"abc"字符串了,所以abc.intern()返回的就是abc2变量指向的常量池字符串地址,所以abc2和abc3指向的地址一样。
String abc = new String("a") + new String("bc");
String abc2 = "abc";
String abc3 = abc.intern();
System.out.println(abc == abc2); //false
System.out.println(abc2 == abc3); //true
在上述面试题中将代码顺序做一下调换则会出现不同结果,如下所示。在这里abc2和abc3的比较没有变化,但是abc和bac2的比较由于jdk版本不同有所变化,这是因为在jdk7以后中已经将intern方法优化,当字符串变量调用intern但是字符串常量池不存在和当前字符串相同的值时则直接将该字符串变量放到字符串常量池中,所以下面代码abc.intern()返回的就是abc的地址。而声明abc2时因为字符串常量池已经存在相同字符串,则直接将字符串常量池中的变量abc的地址赋给了abc2,所以会出现true的情况,而jdk6中并没有上述优化,所以两字符串比较结果还和上面的面试题一样。
String abc = new String("a") + new String("bc");
String abc3 = abc.intern();
String abc2 = "abc";
System.out.println(abc == abc2); //jdk 7之后:true jdk6:false
System.out.println(abc2 == abc3); //true