为什么会写着篇博客, 因为昨天看了关于 final 关键字的解析. 但是有个问题始终没有得到解决, 于是请教了我 qq 上之前添加的知乎大神. 他给我回复的第一条消息: 常量折叠. 身为渣渣猿的我立马查询了这个概念. 这是第一次知道这个概念. 知乎大神还给我讲了好多. 让我终于明白了这个常量折叠的概念
实例解析
昨天, 让我迷惑的代码是下面这段代码
- 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
我就是不明白为什么第一个返回 true 呢?
留着这个疑问, 我们先了解下常量折叠的概念. 来更好的理解上面的代码
常量折叠
常量折叠的概念
常量折叠是一种编译器优化技术.
常量折叠主要指的是编译期常量加减乘除的运算过程会被折叠
对于 String s1 = "1" + "2";
编译器会给你优化成 String s1 = "12";
在生成的字节码中, 根本看不到 "1" "2" 这两个东西.
我们通过 idea 进行验证下
1, 源码文件
- public static void main(String[] args) {
- String s1 = "1"+"2";
- }
2, 运行后, idea 有个 out 文件夹, 找到上面文件的 class 文件
- public static void main(String[] args) {
- String s1 = "12";
- }
确实如上面所说, 编译器会给你进行优化
常量折叠发生的条件
必须是编译期常量之间进行运算才会进行常量折叠.
编译期常量就是 "编译的时候就可以确定其值的常量",
首先: 字面量是编译期常量.(数字字面量, 字符串字面量等)
其次: 编译期常量进行
简单运算的结果
也是编译期常量, 如 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
并且只创建了一个 "abc" 字符串对象, 且位于字符串常量池中.
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 的变量相加, 所以不会进行常量折叠.
而是根据 String 类特有的 + 运算符重载, 变成类似这样的代码
String s2 = new StringBuffer(a).append(b).toString();
这里 toString() 会生成新的 String 变量, 显然用 == 运算符比较是会返回 false.
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 就不是编译器常量
总结
现在看完, 是不是对上面打印的结果为什么是 true 知道了呢?
所以. 只要牢记常量折叠主要指的是编译期常量加减乘除的运算过程会被折叠
来源: https://www.cnblogs.com/zhenghengbin/p/9683990.html