public static String getA() {
return "a";
}
public static void main(String[] args) {
String a = "a";
final String c = "a";
String b = a + "b";
String d = c + "b";
String e = getA() + "b";
String compare = "ab";
System.out.println(b == compare);
System.out.println(d == compare);
System.out.println(e == compare);
}
输出:
false
true
false
编译器优化是有选择的,其实只要记住一句话就行了:只有编译阶段能确定的值,编译器才可以进行优化。
我们回过头来看上面的代码,a
是一个局部变量,后期还可能会被赋值,编译器不确定它的值,所以不会对b
的值进行优化,所以此时在进行+
运算给b
赋值的时候被编译为下面的语句:
StringBuilder temp = new StringBuilder();
temp.append(a).append("b");
String b = temp.toString();
第二个输出为true
,是因为增加了一个final
声明,从而强制约束c
是不可以改变的,编译器知道c
不可改变,所以自然将d
的赋值过程优化,指向静态区ab
的地址;
第三个输出为false
,同样的道理,getA()返回一个常量的引用,但是编译器并不能确切知道函数返回的值是什么,否则需要将函数执行一遍,所以这部分没有进行优化,结果应该为false
。
intern
String a = "a";
String b = a + "b";
String c = "ab";
String d = new String(b);
System.out.println(b == c);
System.out.println(c == d);
System.out.println(c == d.intern());
System.out.println(b.intern() == d.intern());
false
false
true
true
看到上面的结果感到意外吗?其实熟悉了intern
的用法就会明白。
运行时常量池相对于CLass文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入CLass文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用比较多的就是String类的intern()方法.
String的intern()方法会查找在常量池中是否存在一份equal相等的字符串,如果有则返回该字符串的引用,如果没有则添加自己的字符串进入常量池。
网友评论