java之常量折叠

为什么会写着篇博客,因为昨天看了关于final关键字的解析。但是有个问题始终没有得到解决,于是请教了我qq上之前添加的知乎大神。他给我回复的第一条消息:常量折叠。身为渣渣猿的我立马查询了这个概念。这是第一次知道这个概念。知乎大神还给我讲了好多。让我终于明白了这个常量折叠的概念

实例解析

昨天,让我迷惑的代码是下面这段代码

1 public static void main(String[] args) { 2 3 String a = "hello2"; 4 final String b = "hello"; 5 String d = "hello"; 6 String c = b + 2; 7 String e = d + 2; 8 System.out.println((a == c)); 9 System.out.println((a == e)); 10 11 }

这段的执行结果是

1true 2false

我就是不明白为什么第一个返回true呢?

留着这个疑问,我们先了解下常量折叠的概念。来更好的理解上面的代码

常量折叠

常量折叠的概念

  • 常量折叠是一种编译器优化技术。
  • 常量折叠主要指的是编译期常量加减乘除的运算过程会被折叠

对于 String s1 = "1" + "2"; 编译器会给你优化成 String s1 = "12"; 在生成的字节码中,根本看不到 "1" "2" 这两个东西。

我们通过idea进行验证下

1、源码文件

1 public static void main(String[] args) { 2 String s1 = "1"+"2"; 3 }

2、运行后,idea有个out文件夹,找到上面文件的class文件

1 public static void main(String[] args) { 2 String s1 = "12"; 3 }

确实如上面所说,编译器会给你进行优化

常量折叠发生的条件

  • 必须是编译期常量之间进行运算才会进行常量折叠。
  • 编译期常量就是**“编译的时候就可以确定其值的常量”**,
    • 首先:字面量是编译期常量。(数字字面量,字符串字面量等)
    • 其次:编译期常量进行简单运算的结果也是编译期常量,如1+2,"a"+"b"。
    • 最后:被编译器常量赋值的 final 的基本类型和字符串变量也是编译期常量。

举个栗子

1.第一个栗子

1 public static void main(String[] args) { 2 String s1="a"+"bc"; 3 String s2="ab"+"c"; 4 System.out.println(s1 == s2); 5 }

相信大家都知道了,输出为true 并且只创建了一个 "abc" 字符串对象,且位于字符串常量池中。

2、第二个栗子

1 public static void main(String[] args) { 2 String a = "a"; 3 String bc = "bc"; 4 String s1 = "a" + "bc"; 5 String s2 = a + bc; 6 System.out.println(s1 == s2); 7 }

这个结果呢?false

s1 是字符串字面量相加,但是 s2 却是两个非 final 的变量相加,所以不会进行常量折叠。

而是根据 String 类特有的 + 运算符重载,变成类似这样的代码 (jdk1.8)

String s2 = new StringBuilder(a).append(b).toString(); 

这里toString()会生成新的String变量,显然用 == 运算符比较是会返回 false。

3、第三个栗子

1 public static void main(String[] args) { 2 final String a = "a"; 3 final String bc = "bc"; 4 String s1 = "a" + "bc"; 5 String s2 = a + bc; 6 System.out.println(s1 == s2); 7 }

这里的结果就是true

因为 被编译器常量赋值的 final 的基本类型和字符串变量也是编译期常量

4、第四个栗子

1 public static void main(String[] args) { 2 String x ="a"; 3 final String a = x; 4 final String bc = "bc"; 5 String s1 = "a" + "bc"; 6 String s2 = a + bc; 7 System.out.println(s1 == s2); 8 }

这里的结果是false

这里需要注意的是:final的变量,不是被编译期常量初始化的也不是编译器常量

这里的a 就不是编译器常量

5、第五个栗子

1 public static void main(String[] args) { 2 String x ="a"; 3 final String a = x; 4 final String bc = "bc"; 5 String s1 = "a" + "bc"; 6 String s2 = a + bc; 7 System.out.println(s1 == s2.intern()); 8 }

这里的结果是true

其实,这里大家要明白intern这个方法的意思就会明白了

1// 一个字符串池,最初是空的,是由类字符串私有维护的。 21A pool of strings, initially empty, is maintained privately by the class String. 3 4// 如果常量池中已经有了这个字符串,那么直接返回常量池中它的引用,如果没有,那就将它的引用保存一份到字符串常量池,然后直接返回这个引用。 52、When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned. 6 73、It follows that for any two strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is true.

总结

现在看完,是不是对上面打印的结果为什么是true 知道了呢? 所以。只要牢记常量折叠主要指的是编译期常量加减乘除的运算过程会被折叠

后续补充

上面一开始写的是

而是根据 String 类特有的 + 运算符重载,变成类似这样的代码

1String s2 = new StringBuffer(a).append(b).toString(); 2 3

这里更正下,就是现在我用jdk1.8 通过反编译后先在已经不是StringBuffer 而是StringBuilder。这里需要更正下。我也查询了下。StringBuilder 是jdk1.5之后才有的。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

Python之time模块的时间戳、时间字符串格式化与转换

Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。时间元组(struct_time),包含9个元素。 time.struct_time(tm_y

00:Java简单了解

浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。

java之常量折叠 - HelloWorld