java学习教程之常量折叠详解

 更新时间:2018年09月21日 09:01:51   作者:养码青年  
这篇文章主要给大家介绍了关于java学习教程之常量折叠的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用java具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

前言

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

所谓常量折叠是Java在编译期间做的一个优化,简单的来说就是在编译期就把一些表达式计算好,不需要在运行时进行计算。

下面话不多说了,来一起看看详细的介绍吧

实例解析

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

 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 知道了呢?
所以。只要牢记常量折叠主要指的是编译期常量加减乘除的运算过程会被折叠

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

相关文章

  • Java中实现获取路径的方法汇总

    Java中实现获取路径的方法汇总

    本文给大家汇总分享的是Java中实现获取路径的方法,非常的简单实用,需要的小伙伴可以参考下。
    2015-03-03
  • 使用HTTPclient保持长连接

    使用HTTPclient保持长连接

    这篇文章主要介绍了使用HTTPclient保持长连接,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • java导出csv方法实现讲解

    java导出csv方法实现讲解

    这篇文章主要介绍了java导出csv的方法,客户要求在项目中有导出CSV文件的功能,并且给出了如何在不知道如何在不知道对象类型(没有应用泛型)的List中如何得到对象的属性值,下面就详细说下这个功能是如何实现的
    2013-12-12
  • Deep Module深模块之软件设计

    Deep Module深模块之软件设计

    这篇文章主要介绍了软件设计之Deep Module深模块详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • java swing标准对话框具体实现

    java swing标准对话框具体实现

    这篇文章介绍了swing标准对话框的具体实现方法,有需要的朋友可以参考一下
    2013-06-06
  • java学习粗略路线的方法

    java学习粗略路线的方法

    下面小编就为大家带来一篇java学习粗略路线的方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-09-09
  • Java聊天室之使用Socket实现传递图片

    Java聊天室之使用Socket实现传递图片

    这篇文章主要为大家详细介绍了Java简易聊天室之使用Socket实现传递图片功能,文中的示例代码讲解详细,具有一定的借鉴价值,需要的可以了解一下
    2022-10-10
  • 使用Spring初始化加载InitializingBean()方法

    使用Spring初始化加载InitializingBean()方法

    这篇文章主要介绍了使用Spring初始化加载InitializingBean()方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • java项目中的多线程实践记录

    java项目中的多线程实践记录

    项目开发中对于一些数据的处理需要用到多线程,比如文件的批量上传,数据库的分批写入,大文件的分段下载等,主要涉及到多线程的一些知识,本文通过实例代码给大家介绍的非常详细,需要的朋友参考下
    2021-11-11
  • RocketMQ消息发送流程源码剖析

    RocketMQ消息发送流程源码剖析

    这篇文章主要为大家介绍了RocketMQ消息发送流程源码剖析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08

最新评论