日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java擦除

發布時間:2024/4/17 java 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java擦除 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

概述:

? ?Java泛型在使用過程有諸多的問題,如不存在List<String>.class, List<Integer>不能賦值給List<Number>(不可協變),奇怪的ClassCastException等。 正確的使用Java泛型需要深入的了解Java的一些概念,如協變,橋接方法,以及這篇筆記記錄的類型擦除。Java泛型的處理幾乎都在編譯器中進行,編譯器生成的bytecode是不包涵泛型信息的,泛型類型信息將在編譯處理是被擦除,這個過程即類型擦除。

編譯器如何處理泛型:

通常情況下,一個編譯器處理泛型有兩種方式:
?? ? 1.Code specialization
。在實例化一個泛型類或泛型方法時都產生一份新的目標代碼(字節碼or二進制代碼)。例如,針對一個泛型list,可能需要 針對stringintegerfloat產生三份目標代碼。
?? ? 2.Code sharing
。對每個泛型類只生成唯一的一份目標代碼;該泛型類的所有實例都映射到這份目標代碼上,在需要的時候執行類型檢查和類型轉換。
?? ? C++
中的模板(template)是典型的Code specialization實現。C++編譯器會為每一個泛型類實例生成一份執行代碼。執行代碼中integer liststring list是兩種不同的類型。這樣會導致代碼膨脹(code bloat),不過有經驗的C++程序員可以有技巧的避免代碼膨脹。
?? ? Code specialization
另外一個弊端是在引用類型系統中,浪費空間,因為引用類型集合中元素本質上都是一個指針。沒必要為每個類型都產生一份執行代碼。而這也是Java編譯器中采用Code sharing方式處理泛型的主要原因。
?? ? Java
編譯器通過Code sharing方式為每個泛型類型創建唯一的字節碼表示,并且將該泛型類型的實例都映射到這個唯一的字節碼表示上。將多種泛型類形實例映射到唯一的字節碼表示是通過類型擦除(type erasue)實現的。

???類型擦除指的是通過類型參數合并,將泛型類型實例關聯到同一份字節碼上。編譯器只為泛型類型生成一份字節碼,并將其實例關聯到這份字節碼上。類型擦除的關鍵在于從泛型類型中清除類型參數的相關信息,并且再必要的時候添加類型檢查和類型轉換的方法。
?? ??
類型擦除可以簡單的理解為將泛型java代碼轉換為普通java代碼,只不過編譯器更直接點,將泛型java代碼直接轉換成普通java字節碼。
?? ??
類型擦除的主要過程如下:
?? ? 1.
將所有的泛型參數用其最左邊界(最頂級的父類型)類型替換。
?? ? 2.
移除所有的類型參數。

?

擦除使我們在泛型代碼內部,無法獲得任何有關參數類型的信息。很蛋疼...

例如:

C++中我們可以這樣寫:

template<typename T> T imax(T a, T b) {T copy; return copy; } class A{};

  

但是在Java中我們是不能夠生成copy的因為們壓根就不知道T的類型信息。

?

那為什么Java要使用擦除呢?

首先能夠節省空間避免代碼膨脹,主要原因是為了“遷移兼容性”,即允許泛型代碼與非泛型代碼共存,因為泛型是Java后期才添加的為了兼容以前的代碼所以采取了折中的辦法。

那么擦除所帶來的問題我們如何解決呢?

1: 通過引入類型標簽來對擦除進行補償:

class Building{@Overridepublic String toString() {return "Building ...";} } class House extends Building{@Overridepublic String toString() {return "House ...";} }class TestItem<T>{Class<T> type; //通過添加類型標簽,來獲得我要持有的類型的信息public TestItem(Class<T> type) {this.type = type;}public T getInstance() throws InstantiationException, IllegalAccessException {T copy = type.newInstance(); //這樣我就可以利用類型信息進行必要的處理了return copy;} }public class Test {public static void main(String[] args) throws InstantiationException, IllegalAccessException {TestItem<Building> item = new TestItem<>(Building.class);System.out.println(item.getInstance());System.out.println("------------------------");TestItem<House> item2 = new TestItem<>(House.class);System.out.println(item2.getInstance());//出錯,因為我們是利用newInstance來創建對象的,就必須保證我們的對象要有默認的構造方法才行,但是Integer沒有 // System.out.println("------------------------"); // TestItem<Integer> item3 = new TestItem<>(Integer.class); // System.out.println(item3.getInstance());} }

上面的Integer的問題,我們可以通過傳入一個工廠來實現

interface Factory<T>{T create(); } class IntegerFactory implements Factory<Integer> {@Overridepublic Integer create() {return new Integer(0);} }class TestItem<T>{Class<T> type; //通過添加類型標簽,來獲得我要持有的類型的信息T copy;Factory<T> factory;public <F extends Factory<T>>TestItem(F factory) {this.factory = factory;}public TestItem(Class<T> type) {this.type = type;}public T getInstance() throws InstantiationException, IllegalAccessException {//copy = type.newInstance(); //這樣我就可以利用類型信息進行必要的處理了copy = factory.create();return copy;} }public class Test {public static void main(String[] args) throws InstantiationException, IllegalAccessException { // TestItem<Building> item = new TestItem<>(Building.class); // System.out.println(item.getInstance()); // System.out.println("------------------------"); // TestItem<House> item2 = new TestItem<>(House.class); // System.out.println(item2.getInstance());//現在把工廠放進去就可以了。System.out.println("------------------------");TestItem<Integer> item3 = new TestItem<>(new IntegerFactory()); System.out.println(item3.getInstance());} }

  

2: 同樣我們可以通過使用設置擦相互邊界來補償擦除

就像我們在前一篇的比較的時候我們將擦除邊界設定成了Comparable,保證了我們的類新信息是可比較的。

http://www.cnblogs.com/E-star/p/3438226.html

?

注意:

1.虛擬機中沒有泛型,只有普通類和普通方法
2.
所有泛型類的類型參數在編譯時都會被擦除
3.
創建泛型對象時請指明類型,讓編譯器盡早的做參數檢查(Effective Java,第23條:請不要在新代碼中使用原生態類型)
4.
不要忽略編譯器的警告信息,那意味著潛在的ClassCastException等著你。

?

?

轉載于:https://www.cnblogs.com/E-star/p/3438290.html

總結

以上是生活随笔為你收集整理的Java擦除的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。