65.Java语法糖
65.Java語法糖
語法糖(Syntactic Sugar),也稱糖衣語法,是由英國計算機學家 Peter.J.Landin 發明的一個術語,指在計算機語言中添加的某種語法,這種語法對語言的功能并沒有影響,但是更方便程序員使用。Java 中最常用的語法糖主要有泛型、變長參數、條件編譯、自動拆裝箱、內部類等。虛擬機并不支持這些語法,它們在編譯階段就被還原回了簡單的基礎語法結構,這個過程成為解語法糖。
泛型是 JDK1.5 之后引入的一項新特性,Java 語言在還沒有出現泛型時,只能通過 Object 是所有類型的父類和類型強制轉換這兩個特點的配合來實現泛型的功能,這樣實現的泛型功能要在程序運行期才能知道 Object 真正的對象類型,在 javac 編譯期,編譯器無法檢查這個 Object 的強制轉型是否成功,這便將一些風險轉接到了程序運行期中。
Java 語言在 JDK1.5 之后引入的泛型實際上只在程序源碼中存在,在編譯后的字節碼文件中,就已經被替換為了原來的原生類型,并且在相應的地方插入了強制轉型代碼,因此對于運行期的Java語言來說,ArrayList和 ArrayList就是同一個類。所以泛型技術實際上是 Java 語言的一顆語法糖,Java 語言中的泛型實現方法稱為類型擦除,基于這種方法實現的泛型被稱為偽泛型。
下面是一段簡單的 Java 泛型代碼:
Map<Integer,String> map = new HashMap<Integer,String>(); map.put(1,"No.1"); map.put(2,"No.2"); System.out.println(map.get(1)); System.out.println(map.get(2));將這段 Java 代碼編譯成 Class 文件,然后再用字節碼反編譯工具進行反編譯后,將會發現泛型都變回了原生類型,如下面的代碼所示:
Map map = new HashMap(); map.put(1,"No.1"); map.put(2,"No.2"); System.out.println((String)map.get(1)); System.out.println((String)map.get(2));為了更詳細地說明類型擦除,再看如下代碼:
import java.util.List; public class FanxingTest{ public void method(List<String> list){ System.out.println("List String"); } public void method(List<Integer> list){ System.out.println("List Int"); } }當用 javac 編譯器編譯這段代碼時,報出了如下錯誤:
FanxingTest.java:3: 名稱沖突:method(java.util.List<java.lang.String>) 和 method(java.util.List<java.lang.Integer>) 具有相同疑符public void method(List<String> list){^FanxingTest.java:6: 名稱沖突:method(java.util.List<java.lang.Integer>) 和 method(java.util.List<java.lang.String>) 具有相同疑符public void method(List<Integer> list){^2 錯誤
是因為泛型 List 和 List 編譯后都被擦除了,變成了一樣的原生類型 List,擦除動作導致這兩個方法的特征簽名變得一模一樣,在 Class 類文件結構一文中講過,Class 文件中不能存在特征簽名相同的方法。
把以上代碼修改如下:
發現這時編譯可以通過了(注意:Java 語言中 true 和 1 沒有關聯,二者屬于不同的類型,不能相互轉換,不存在 C 語言中整數值非零即真的情況)。兩個不同類型的返回值的加入,使得方法的重載成功了。這是為什么呢?
我們知道,Java 代碼中的方法特征簽名只包括了方法名稱、參數順序和參數類型,并不包括方法的返回值,因此方法的返回值并不參與重載方法的選擇,這樣看來為重載方法加入返回值貌似是多余的。對于重載方法的選擇來說,這確實是多余的,但我們現在要解決的問題是讓上述代碼能通過編譯,讓兩個重載方法能夠合理地共存于同一個 Class 文件之中,這就要看字節碼的方法特征簽名,它不僅包括了 Java 代碼中方法特征簽名中所包含的那些信息,還包括方法返回值及受查異常表。為兩個重載方法加入不同的返回值后,因為有了不同的字節碼特征簽名,它們便可以共存于一個 Class 文件之中。
自動拆裝箱、變長參數等語法糖也都是在編譯階段就把它們該語法糖結構還原為了原生的語法結構,因此在 Class 文件中也只存在其對應的原生類型,這里不再一一說明。
總結
以上是生活随笔為你收集整理的65.Java语法糖的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 64.多态性实现机制—静态分派与动态分派
- 下一篇: 67.Java垃圾收集机制\对象引用\垃