一:常见面试题:
1.阅读一下程序,说说输出结果是什么?为什么会是这样?
public static void main(String[] args) { String a = "hello2"; final String b = "hello"; String d = "hello"; String c = b + 2; String e = d + 2; System.out.println((a == c)); System.out.println((a == e)); }
结果为:true,false,是不是大多数小伙伴懵逼了,为什么不一样,为什么final修饰会是 true?.....我们带着若干疑问,来先了解了解java中的常量折叠。
二:深度剖析java中的常量折叠
(一):常量折叠原理:
所谓常量折叠是Java在编译期间做的一个优化,简单的来说就是在编译期就把一些表达式计算好,不需要在运行时进行计算。它是一种编译器优化技术。主要指的是编译期常量加减乘除的运算过程会被折叠。举个例子,int num = 2 + 3,int str = "a" + "b",这些经过常量折叠后就会变为int num = 5,str = "ab"等,是不是通俗易懂,非常好理解。
(二):总结常量折叠发生的条件:
必须是编译期常量之间进行运算才会进行常量折叠。编译期常量就是“编译的时候就可以确定其值的常量”。比如,首先:字面量是编译期常量。(数字字面量,字符串字面量等)其次:编译期常量进行简单运算的结果也是编译期常量,如1+2,“a”+“b”。最后:被编译器常量赋值的 final 的基本类型和字符串变量也是编译期常量。所以,刚开始有点懵的面试题直到原因了吗。
三:小试牛刀,温故知新
1.
public static void main(String[] args) { String s1 = "a" + "bc"; String s2 = "ab" + "c"; System.out.println(s1 == s2); }
是不是非常简单,常量折叠后,就是一个对象,所以结果肯定是true.
2.
public static void main(String[] args) { String a = "a"; String bc = "bc"; String s1 = "a" + "bc"; String s2 = a + bc; System.out.println(s1 == s2); }
这个结果呢?false,s1 是字符串字面量相加,但是 s2 却是两个非 final 的变量相加,所以不会进行常量折叠.
3.
public static void main(String[] args) { final String a = "a"; final String bc = "bc"; String s1 = "a" + "bc"; String s2 = a + bc; System.out.println(s1 == s2); }
这里的结果就是true,因为 被编译器常量赋值的 final 的基本类型和字符串变量也是编译期常量.
4.
public static void main(String[] args) { String x = "a"; final String a = x; final String bc = "bc"; String s1 = "a" + "bc"; String s2 = a + bc; System.out.println(s1 == s2); }
这里的结果是false,这里需要注意的是:final的变量,不是被编译期常量初始化的也不是编译器常量,这里的a 就不是编译器常量.