java學(xué)習(xí)教程之常量折疊詳解
前言
為什么會寫著篇博客,因?yàn)樽蛱炜戳岁P(guān)于final關(guān)鍵字的解析。但是有個問題始終沒有得到解決,于是請教了我qq上之前添加的知乎大神。他給我回復(fù)的第一條消息:常量折疊。身為渣渣猿的我立馬查詢了這個概念。這是第一次知道這個概念。知乎大神還給我講了好多。讓我終于明白了這個常量折疊的概念
所謂常量折疊是Java在編譯期間做的一個優(yōu)化,簡單的來說就是在編譯期就把一些表達(dá)式計算好,不需要在運(yùn)行時進(jìn)行計算。
下面話不多說了,來一起看看詳細(xì)的介紹吧
實(shí)例解析
昨天,讓我迷惑的代碼是下面這段代碼
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)); }
這段的執(zhí)行結(jié)果是
true
false
我就是不明白為什么第一個返回true呢?
留著這個疑問,我們先了解下常量折疊的概念。來更好的理解上面的代碼
常量折疊
常量折疊的概念
- 常量折疊是一種編譯器優(yōu)化技術(shù)。
- 常量折疊主要指的是編譯期常量加減乘除的運(yùn)算過程會被折疊
對于 String s1 = "1" + "2";
編譯器會給你優(yōu)化成 String s1 = "12";
在生成的字節(jié)碼中,根本看不到 "1" "2" 這兩個東西。
我們通過idea進(jìn)行驗(yàn)證下
1、源碼文件
public static void main(String[] args) { String s1 = "1"+"2"; }
2、運(yùn)行后,idea有個out文件夾,找到上面文件的class文件
public static void main(String[] args) { String s1 = "12"; }
確實(shí)如上面所說,編譯器會給你進(jìn)行優(yōu)化
常量折疊發(fā)生的條件
必須是編譯期常量之間進(jìn)行運(yùn)算才會進(jìn)行常量折疊。
編譯期常量就是“編譯的時候就可以確定其值的常量”,
- 首先:字面量是編譯期常量。(數(shù)字字面量,字符串字面量等)
- 其次:編譯期常量進(jìn)行簡單運(yùn)算的結(jié)果也是編譯期常量,如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
并且只創(chuàng)建了一個 "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); }
這個結(jié)果呢?false
s1 是字符串字面量相加,但是 s2 卻是兩個非 final 的變量相加,所以不會進(jìn)行常量折疊。
而是根據(jù) String 類特有的 + 運(yùn)算符重載,變成類似這樣的代碼
String s2 = new StringBuffer(a).append(b).toString();
這里toString()會生成新的String變量,顯然用 == 運(yùn)算符比較是會返回 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); }
這里的結(jié)果就是true
因?yàn)?被編譯器常量賦值的 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); }
這里的結(jié)果是false
這里需要注意的是:final的變量,不是被編譯期常量初始化的也不是編譯器常量
這里的a 就不是編譯器常量
總結(jié)
現(xiàn)在看完,是不是對上面打印的結(jié)果為什么是true 知道了呢?
所以。只要牢記常量折疊主要指的是編譯期常量加減乘除的運(yùn)算過程會被折疊
好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
Springboot通過Scheduled實(shí)現(xiàn)定時任務(wù)代碼
這篇文章主要介紹了Springboot通過Scheduled實(shí)現(xiàn)定時任務(wù)代碼,具有一定參考價值,需要的朋友可以了解下。2017-11-11Java實(shí)現(xiàn)文件或文件夾的復(fù)制到指定目錄實(shí)例
本篇文章主要介紹了Java實(shí)現(xiàn)文件或文件夾的復(fù)制到指定目錄實(shí)例,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-03-03Java實(shí)現(xiàn)獲取Excel中的表單控件
Excel中可通過【開發(fā)工具】菜單欄下插入表單控件,如文本框、單選按鈕、復(fù)選框、組合框等等。本文將利用Java實(shí)現(xiàn)獲取Excel中的表單控件,需要的可以參考一下2022-05-05MyBatis實(shí)現(xiàn)多表聯(lián)查的詳細(xì)代碼
這篇文章主要介紹了MyBatis如何實(shí)現(xiàn)多表聯(lián)查,通過實(shí)例代碼給大家介紹使用映射配置文件實(shí)現(xiàn)多表聯(lián)查,使用注解的方式實(shí)現(xiàn)多表聯(lián)查,需要的朋友可以參考下2022-08-08struts2攔截器_動力節(jié)點(diǎn)Java學(xué)院整理
如何使用struts2攔截器,或者自定義攔截器。下面通過實(shí)例代碼給大家分享struts2攔截器的相關(guān)知識,感興趣的朋友參考下吧2017-09-09Java this super代碼實(shí)例及使用方法總結(jié)
這篇文章主要介紹了Java this super代碼實(shí)例及使用方法總結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03Java使用泛型Class實(shí)現(xiàn)消除模板代碼
Class作為實(shí)現(xiàn)反射功能的類,在開發(fā)中經(jīng)常會用到,然而,當(dāng)Class遇上泛型后,事情就變得不是那么簡單了,所以本文就來講講Java如何使用泛型Class實(shí)現(xiàn)消除模板代碼,需要的可以參考一下2023-06-06