java关于String的编译优化

2019-11-10  本文已影响0人  CarsonCao
   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相等的字符串,如果有则返回该字符串的引用,如果没有则添加自己的字符串进入常量池。

上一篇下一篇

猜你喜欢

热点阅读