很久之前學(xué)習(xí)過 a=a+b 和a+=b的一些區(qū)別,進(jìn)來再次回想起來,發(fā)現(xiàn)理解的還不透徹,所以又查資料找文件重新學(xué)習(xí)了一番。 比較這兩種運(yùn)算符的區(qū)別,可以有以下兩個(gè)方面的比較: 執(zhí)行效率和類型轉(zhuǎn)換。 首先說一下執(zhí)行效率問題 就單純的執(zhí)行這兩條語句,不考慮編譯器的優(yōu)化的話,a=a+b的執(zhí)行效率是低于a+=b的,因?yàn)樗噙M(jìn)行了一步中間變量的操作,而且會(huì)多占用一個(gè)變量的空間。而Java編譯器默認(rèn)對(duì)其進(jìn)行了優(yōu)化,優(yōu)化之后兩條語句都當(dāng)做 a+=b來執(zhí)行了,所以實(shí)際上是沒有任何卻別的。 其次說一下有關(guān)類型轉(zhuǎn)換的區(qū)別。 相信大家都碰到過這種情況: public class Test { 當(dāng)使用a=a+b的時(shí)候,會(huì)拋出”Exception in thread "main" java.lang.Error: Unresolved compilation problem: Type mismatch: cannot convert from float to int“的異常,這是可以理解的,如果不使用(int)強(qiáng)制類型轉(zhuǎn)換的話,float 是不能直接復(fù)值給int 變量的。 我們將a=a+b注釋掉,javac編譯完之后,再使用反編譯軟件(例如XJad)打開Test.class文件,會(huì)發(fā)現(xiàn)源代碼被解析成這樣子: public class Test public Test() public static void main(String args[]) 即a+=b進(jìn)行了強(qiáng)制類型轉(zhuǎn)換,和 a=(int)((float)a+b)是等價(jià)的! 到這里我們就明白了為什么a=a+b會(huì)拋出異常了。 原因:在Java中,在基本類型進(jìn)行算術(shù)運(yùn)算的時(shí)候,會(huì)發(fā)生小字節(jié)類型向大字節(jié)類型轉(zhuǎn)換的現(xiàn)象。如圖中 int 類型和float類型進(jìn)行加法運(yùn)算時(shí)會(huì)將 a 先轉(zhuǎn)換為float類型,然后再和b相加。這樣結(jié)果類型變成了float類型,如果這時(shí)候試圖把float類型賦值給a時(shí)便會(huì)拋異常。 另外,對(duì)于short,byte,char 比int 字節(jié)數(shù)小的變量類型來說,運(yùn)算結(jié)果會(huì)自動(dòng)轉(zhuǎn)換為int類型,如 byte a = 1 , b=2; byte a = 1; 都會(huì)拋出”Exception in thread "main" java.lang.Error: Unresolved compilation problem: Type mismatch: cannot convert from int to byte“類似的異常,可以看出a+b結(jié)果變成了int類型。 這是由于Java編譯器會(huì)在編譯期或者運(yùn)行期將byte和short類型的數(shù)據(jù)帶符號(hào)擴(kuò)展為相應(yīng)的int類型數(shù)據(jù),將boolean和char類型數(shù)據(jù)零位擴(kuò)展為相應(yīng)的int類型數(shù)據(jù)。因此,在處理boolean 、byte、short 和 char 類型的數(shù)組是,也會(huì)用相應(yīng)的int類型的字節(jié)碼指令來處理。因此,大多數(shù)對(duì)于上述類型數(shù)據(jù)的操作,實(shí)際上都是使用相應(yīng)的 int 類型作為運(yùn)算類型。 如果是final 修飾的變量,進(jìn)行運(yùn)算的時(shí)候則不會(huì)出現(xiàn)類型轉(zhuǎn)換異常。 public class Test { 編譯后使用反編譯軟件打開后,代碼被解析成了這樣: public class Test final int d = 3; public Test() public static void main(String args[]) 可以看到,對(duì)于final 修飾的基本類型的變量來說,他們之間的運(yùn)算直接就被硬編碼成了直接賦值語句,連中間結(jié)果都沒有了,類型轉(zhuǎn)換的異常也就沒了。 此外,我們可以注意到,對(duì)于方法內(nèi)的final 變量 a , b 來說,編碼時(shí)被直接省略了。而Test 類的final 成員變量 d 依然保留著final 屬性。 所以說,是否使用final修飾方法中普通變量對(duì)JVM來說沒有區(qū)別!使用final修飾方法中普通變量主要是為了給Java前端編譯器(如javac)看的!也就是說方法中被final修飾的普通變量在前端編譯時(shí)被javac檢查并保證該變量不會(huì)在作用域內(nèi)被改變新值,但被編譯成字節(jié)碼后用于修飾方法中普通變量的final就已經(jīng)不存在了!說的再具體點(diǎn)就是你用或不用final修飾方法中普通變量而生成的字節(jié)碼文件(.class文件)沒有區(qū)別。 PS:對(duì)于final 修飾的類成員來說,由于其生命周期在對(duì)象銷毀之前,所以它占用的應(yīng)該是堆內(nèi)存。(這個(gè)不確定 --) Java 9 的新特性發(fā)布 http://www./Linux/2014-08/105707.htm Java編程思想(第4版) 中文清晰PDF完整版 http://www./Linux/2014-08/105403.htm 編寫高質(zhì)量代碼 改善Java程序的151個(gè)建議 PDF高清完整版 http://www./Linux/2014-06/103388.htm Java 8簡(jiǎn)明教程 http://www./Linux/2014-03/98754.htm Java對(duì)象初始化順序的簡(jiǎn)單驗(yàn)證 http://www./Linux/2014-02/96220.htm Java對(duì)象值傳遞和對(duì)象傳遞的總結(jié) http://www./Linux/2012-12/76692.htm 本文永久更新鏈接地址:http://www./Linux/2014-09/106764.htm |
|