java之常量折叠
为什么会写着篇博客,因为昨天看了关于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 类特有的 + 运算符重载,变成类似这样的代码 (jdk1.8)
String s2 = new StringBuilder(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 就不是编译器常量
5、第五个栗子
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.intern());
}
这里的结果是true
其实,这里大家要明白intern这个方法的意思就会明白了
// 一个字符串池,最初是空的,是由类字符串私有维护的。
1、A pool of strings, initially empty, is maintained privately by the class String.
// 如果常量池中已经有了这个字符串,那么直接返回常量池中它的引用,如果没有,那就将它的引用保存一份到字符串常量池,然后直接返回这个引用。
2、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.
3、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 类特有的 + 运算符重载,变成类似这样的代码
String s2 = new StringBuffer(a).append(b).toString();
这里更正下,就是现在我用jdk1.8 通过反编译后先在已经不是StringBuffer 而是StringBuilder。这里需要更正下。我也查询了下。StringBuilder 是jdk1.5之后才有的。
java之常量折叠的更多相关文章
- C++中的常量折叠
先看例子: #include <iostream> using namespace std; int main() { ; int * p = (int *)(&a); *p = ...
- 常量折叠 const folding
http://bbs.byr.cn/#!article/CPP/86336?p=1 下列代码给出输出结果: #include"stdafx.h" #include <iost ...
- eclipse中,把java函数代码折叠/展开
首先,在eclipse 中开启设置代码折叠功能 1. windows->perferences->General->Editors->Structured Text Edito ...
- const常量折叠
首先来看一个例子: int main(int argc, char* argv[]) { ; int *j = (int *) &i; *j=; cout<<&i<& ...
- C++的常量折叠(二)
前面的C++的常量折叠(一)的最后留下了一个问题,那就是在声明i的时候,加上修饰符volatile关键字,发现结果输出的就不一样了,下面来说一下volatile这个关键字. C/C++中的volati ...
- C++的常量折叠(一)
前言 前几天女票问了我一个阿里的面试题,是有关C++语言的const常量的,其实她一提出来我就知道考察的点了:肯定是const常量的内存不是分配在read-only的存储区的,const常量的内存分配 ...
- -1-1 java 基础语法 java关键字 java 注释 常量 语句 运算符 函数 数组定义
Java语言基础组成 关键字 标识符 注释 常量和变量 运算符 语句 函数 数组 关键字 定义:被Java语言赋予了特殊含义的单词 特点:关键字中所有字母都为小写 用于定义数据类型的关键字 class ...
- java中常量文件的配置与读取
java中常量文件的配置与读取: package com.floor.shop.user.util; import java.io.InputStream; import java.io.InputS ...
- JAVA编译器常量
编译器常量的特点就是:它的值在编译期就可以确定.比如: final int i = 5; 再傻的编译器也能在编译时看出它的值是5,不需要到运行时.对于运行时常量,它的值虽然在运行时初始化后不再发生变化 ...
随机推荐
- 理解javascript观察者模式(订阅者与发布者)
什么是观察者模式? 观察者模式又叫做发布订阅模式,它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生改变时就会通知所有观察着对象.它是由两类对象组成,主题和观察者 ...
- 树莓派学习笔记(2):常用linux命令
转载请注明:@小五义http://www.cnblogs.com/xiaowuyi 1.ls命令:列出文件目录的常用命令,主要参数见下表. -a 列出目录下的所有文件,包括以.开头的隐含文件. -b ...
- 执行力:Just Do It
执行力,最最关键的一点就是,立即去做,不要想太多. 当有一件事需要去做的时候,你的大脑肯定是接受到了"某种信号",比如来了一个灵感.受到一点启发.做某件事突然来了兴趣.或者想去探讨 ...
- 汇编 (NOT)按位取反指令
知识点: (NOT)按位取反指令 逻辑取反(!) 按位取反(~) SETZ(SETE) 取ZF位值保存 SETNZ(SETNE)将ZF位值取反后保存 一.逻辑取反(!) !111 ...
- Java 中的 try catch 影响性能吗?
前几天在 code review 时发现有一段代码中存在滥用try catch的现象.其实这种行为我们也许都经历过,刚参加工作想尽量避免出现崩溃问题,因此在很多地方都想着 try catch一下. 但 ...
- spring cloud资料汇总
https://www.cnblogs.com/Java3y/p/9540386.html#commentform --非常好的文章,里面还有海量学习资料
- 如何设计一个异步Web服务——接口部分
需求比较简单,提供一个异步Web服务供使用者调用.比如说,某应用程序需要批量地给图片加lomo效果.由于加lomo效果这个操作非常消耗CPU资源,所以我们需要把这个加lomo效果的程序逻辑放到一台单独 ...
- 通过C#的HttpClient模拟form表单请求
post提交表单一般无非是一般text文本和文件类型,如下 <input type="file"/> <input type="text"/& ...
- 阿里云配置ssl证书
一.申请证书和下载证书(阿里云申请) 二.在nginx服务器上配置ssl证书 1.检查服务器是否安装openssl 2.在nginx conf 文件夹创建 cret 文件,放置证书 [root@web ...
- package.json 中 npm 依赖包版本前的符号的意义
版本的格式 major.minor.patch:主版本号.次版本号.修补版本号 patch:修复bug,兼容老版本 minor:新增功能,兼容老版本 major:新增功能,不兼容老版本 version ...