摘要:提供給了用戶大量的語(yǔ)法糖,比如泛型自動(dòng)裝箱拆箱循環(huán)變長(zhǎng)參數(shù)內(nèi)部類(lèi)枚舉類(lèi)斷言新特性方法引用等解語(yǔ)法糖語(yǔ)法糖的存在主要是方便開(kāi)發(fā)人員使用。
首先,部分總結(jié)文字引用 簡(jiǎn)書(shū)作者:Eric新之助 。鏈接:https://www.jianshu.com/p/4de08deb6ba4
已獲得授權(quán)
先簡(jiǎn)單了解下定義
語(yǔ)法糖語(yǔ)法糖(Syntactic Sugar),也叫糖衣語(yǔ)法,是英國(guó)計(jì)算機(jī)科學(xué)家彼得·約翰·蘭達(dá)(Peter J. Landin)發(fā)明的一個(gè)術(shù)語(yǔ)。指的是,在計(jì)算機(jī)語(yǔ)言中添加某種語(yǔ)法,這種語(yǔ)法能使程序員更方便的使用語(yǔ)言開(kāi)發(fā)程序,同時(shí)增強(qiáng)程序代碼的可讀性,避免出錯(cuò)的機(jī)會(huì)。
幾乎每種語(yǔ)言都提供語(yǔ)法糖,它只是編譯器實(shí)現(xiàn)的一些小把戲罷了,編譯期間以特定的字節(jié)碼或者特定的方式對(duì)這些語(yǔ)法做一些處理,開(kāi)發(fā)者就可以直接方便地使用了。這些語(yǔ)法糖雖然不會(huì)提供實(shí)質(zhì)性的功能改進(jìn),但是它們或能提高性能、或能提升語(yǔ)法的嚴(yán)謹(jǐn)性、或能減少編碼出錯(cuò)的機(jī)會(huì)。Java提供給了用戶大量的語(yǔ)法糖,比如泛型、自動(dòng)裝箱/拆箱、foreach循環(huán)、變長(zhǎng)參數(shù)、內(nèi)部類(lèi)、枚舉類(lèi)、斷言、JAVA8新特性(lambda、stream、方法引用等)......
語(yǔ)法糖的存在主要是方便開(kāi)發(fā)人員使用。但其實(shí),Java 虛擬機(jī)并不支持這些語(yǔ)法糖,這些語(yǔ)法糖在編譯階段就會(huì)被還原成簡(jiǎn)單的基礎(chǔ)語(yǔ)法結(jié)構(gòu),這個(gè)過(guò)程就是解語(yǔ)法糖。
說(shuō)到編譯,大家肯定都知道,Java 語(yǔ)言中,javac命令可以將后綴名為.java的源文件編譯為后綴名為.class的可以運(yùn)行于 Java 虛擬機(jī)的字節(jié)碼。
如果你去看com.sun.tools.javac.main.JavaCompiler的源碼,你會(huì)發(fā)現(xiàn)在compile()中有一個(gè)步驟就是調(diào)用desugar(),這個(gè)方法就是負(fù)責(zé)解語(yǔ)法糖的實(shí)現(xiàn)的。
學(xué)習(xí)語(yǔ)法糖原理最好的辦法就是反編譯看源碼~
反編譯工具:
IDEA默認(rèn)反編譯內(nèi)置插件: JD-IntelliJ
對(duì)java8支持良好的反編譯工具: procyon-decompiler
使用方法 : java -jar (jar包路徑)procyon-decompiler-0.5.30.jar(class文件路徑)*.class
只支持到j(luò)dk1.5的反編譯工具: jad
使用方法 : jad -o -8 -r -d(輸出反編譯文件路徑) -sjava (class文件路徑)下面看看語(yǔ)法糖和三種反編譯器編譯后的代碼 可變長(zhǎng)度參數(shù)
可變參數(shù)由數(shù)組實(shí)現(xiàn)
Ps:可變長(zhǎng)度參數(shù)必須作為方法參數(shù)列表中的的最后一個(gè)參數(shù)且方法參數(shù)列表中只能有一個(gè)可變長(zhǎng)度參數(shù)
對(duì)于數(shù)組,foreach是用普通for循環(huán)實(shí)現(xiàn)的。
說(shuō)明在對(duì)有實(shí)現(xiàn)Iterable接口的對(duì)象采用foreach語(yǔ)法糖的話,編譯器會(huì)將這個(gè)for關(guān)鍵字轉(zhuǎn)化為對(duì)目標(biāo)的迭代器使用。
所以如果想要自己自定義的類(lèi)可以采用foreach語(yǔ)法糖就要實(shí)現(xiàn)Iterable接口了。
可以看到在自動(dòng)裝箱的時(shí)候,Java虛擬機(jī)會(huì)自動(dòng)調(diào)用Integer的valueOf方法;
在自動(dòng)拆箱的時(shí)候,Java虛擬機(jī)會(huì)自動(dòng)調(diào)用Integer的intValue方法。這就是自動(dòng)拆箱和自動(dòng)裝箱的原理
代碼:
IDEA反編譯:
procyon-decompiler反編譯:
jad反編譯:
泛型與類(lèi)型擦除對(duì)于java虛擬機(jī)來(lái)說(shuō),他根本不認(rèn)識(shí)Map
類(lèi)型擦除的主要過(guò)程如下:
將所有的泛型參數(shù)用其最左邊界(最頂級(jí)的父類(lèi)型)類(lèi)型替換。 移除所有的類(lèi)型參數(shù)。
代碼:
IDEA反編譯:
procyon-decompiler反編譯:
jad反編譯:
泛型與重載泛型編譯出來(lái)的代碼是會(huì)把類(lèi)型擦除的,所以如下的代碼是不能編譯的,是因?yàn)閰?shù)List
那么如果加上返回類(lèi)型呢?
上面這段代碼,IDE無(wú)法編譯通過(guò),javac編譯可以通過(guò)。
網(wǎng)上找到一段引用:
在《Java虛擬機(jī)規(guī)范第二版》(JDK 1.5修改后的版本)的“§4.4.4
Signatures”章節(jié)及《Java語(yǔ)言規(guī)范第三版》的“§8.4.2 Method
Signature”章節(jié)中分別都定義了字節(jié)碼層面的方法特征簽名,以及Java代碼層面的方法特征簽名,特征簽名最重要的任務(wù)就是作為方法獨(dú)一無(wú)二不可重復(fù)的ID,在Java代碼中的方法特征簽名只包括了方法名稱、參數(shù)順序及參數(shù)類(lèi)型,而在字節(jié)碼中的特征簽名還包括方法返回值及受查異常表。
根據(jù)上面的例子說(shuō)明:由于List
Java枚舉編譯后實(shí)際上是生成了一個(gè)類(lèi),該類(lèi)繼承了 java.lang.Enum
代碼:
IDEA反編譯:
procyon-decompiler反編譯:
jad反編譯:
內(nèi)部類(lèi)Java的內(nèi)部類(lèi)也是一個(gè)語(yǔ)法糖,它僅僅是一個(gè)編譯時(shí)的概念,outer.java里面定義了一個(gè)內(nèi)部類(lèi)inner,一旦編譯成功,就會(huì)生成兩個(gè)完全不同的.class文件了,分別是outer.class和outer$inner.class。所以內(nèi)部類(lèi)的名字完全可以和它的外部類(lèi)名字相同。
代碼:
IDEA反編譯:
procyon-decompiler反編譯:
jad反編譯:
Parsing /Users/dasouche/Downloads/product/springboot-demo/target/classes/com/example/demo/DemoOutClass.class...Parsing inner class /Users/dasouche/Downloads/product/springboot-demo/target/classes/com/example/demo/DemoOutClass$InnerClass.class... Generating /Users/dasouche/Desktop/jad158g.mac.intel/com/example/demo/DemoOutClass.java斷言
代碼:
IDE反編譯:
procyon-decompiler反編譯:
jad反編譯:
JAVA8新特性中語(yǔ)法糖Lambda表達(dá)式在Java 8中首先會(huì)生成一個(gè)私有的靜態(tài)函數(shù),這個(gè)私有的靜態(tài)函數(shù)干的就是Lambda表達(dá)式里面的內(nèi)容
代碼:
IDEA反編譯:
procyon-decompiler反編譯:
jad反編譯 報(bào)錯(cuò):
用javap反編譯后:
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/76757.html
摘要:但其實(shí),虛擬機(jī)并不支持這些語(yǔ)法糖。方式為每個(gè)泛型類(lèi)型創(chuàng)建唯一的字節(jié)碼表示,并且將該泛型類(lèi)型的實(shí)例都映射到這個(gè)唯一的字節(jié)碼表示上。GitHub 2.5k Star 的Java工程師成神之路 ,不來(lái)了解一下嗎); GitHub 2.5k Star 的Java工程師成神之路 ,真的不來(lái)了解一下嗎); GitHub 2.5k Star 的Java工程師成神之路 ,真的確定不來(lái)了解一下嗎); 本文從 ...
摘要:但其實(shí),虛擬機(jī)并不支持這些語(yǔ)法糖。方式為每個(gè)泛型類(lèi)型創(chuàng)建唯一的字節(jié)碼表示,并且將該泛型類(lèi)型的實(shí)例都映射到這個(gè)唯一的字節(jié)碼表示上。GitHub 2.5k Star 的Java工程師成神之路 ,不來(lái)了解一下嗎); GitHub 2.5k Star 的Java工程師成神之路 ,真的不來(lái)了解一下嗎); GitHub 2.5k Star 的Java工程師成神之路 ,真的確定不來(lái)了解一下嗎); 本文從 ...
摘要:但其實(shí),虛擬機(jī)并不支持這些語(yǔ)法糖。方式為每個(gè)泛型類(lèi)型創(chuàng)建唯一的字節(jié)碼表示,并且將該泛型類(lèi)型的實(shí)例都映射到這個(gè)唯一的字節(jié)碼表示上。GitHub 2.5k Star 的Java工程師成神之路 ,不來(lái)了解一下嗎); GitHub 2.5k Star 的Java工程師成神之路 ,真的不來(lái)了解一下嗎); GitHub 2.5k Star 的Java工程師成神之路 ,真的確定不來(lái)了解一下嗎); 本文從 ...
摘要:操作對(duì)應(yīng)字節(jié)碼中的個(gè)字節(jié)我們可以看到最關(guān)鍵的操作其實(shí)就是調(diào)用的其實(shí)是類(lèi)的方法,此方法的入?yún)㈩?lèi)型是,返回值類(lèi)型是,翻譯過(guò)來(lái)就是類(lèi)的方法,執(zhí)行完后將獲得的結(jié)果做了,檢查返回的對(duì)象類(lèi)型是否是。 語(yǔ)法糖(Syntactic Sugar)的出現(xiàn)是為了降低我們編寫(xiě)某些代碼時(shí)陷入的重復(fù)或繁瑣,這使得我們使用語(yǔ)法糖后可以寫(xiě)出簡(jiǎn)明而優(yōu)雅的代碼。在Java中不加工的語(yǔ)法糖代碼運(yùn)行時(shí)可不會(huì)被虛擬機(jī)接受,因此...
摘要:因此,對(duì)應(yīng)地我們可以翻譯這段二進(jìn)制字節(jié)碼為這樣的代碼注意,這段代碼并不能通過(guò)編譯,因?yàn)樵创a這一層是不允許直接繼承的,這個(gè)繼承過(guò)程只允許在編譯器內(nèi)部解語(yǔ)法糖的過(guò)程中被編譯器添加,添加之后的類(lèi)才會(huì)有的訪問(wèn)標(biāo)識(shí)符。 語(yǔ)法糖(Syntactic Sugar)的出現(xiàn)是為了降低我們編寫(xiě)某些代碼時(shí)陷入的重復(fù)或繁瑣,這使得我們使用語(yǔ)法糖后可以寫(xiě)出簡(jiǎn)明而優(yōu)雅的代碼。在Java中不加工的語(yǔ)法糖代碼運(yùn)行時(shí)可...
閱讀 3288·2023-04-26 01:58
閱讀 1025·2021-11-24 09:38
閱讀 3363·2021-09-03 10:29
閱讀 783·2021-08-21 14:10
閱讀 1546·2019-08-30 15:44
閱讀 3158·2019-08-30 14:10
閱讀 3284·2019-08-29 16:32
閱讀 1537·2019-08-29 12:48