摘要:泛型類型僅存在于編譯期間,編譯后的字節(jié)碼和運(yùn)行時不包含泛型信息,所有的泛型類型映射到同一份字節(jié)碼。的本質(zhì)泛型編譯器原始類型被替換泛型編譯器原始類型被替換原始類型指被編譯器擦除了泛型信息后,類型變量在字節(jié)碼中的具體類型。
type erasure & reified generic
Java的泛型不同于C++的模板:Java泛型是"type erasure",C++模板是"reified generic"。
type erasure:泛型類型僅存在于編譯期間,編譯后的字節(jié)碼和運(yùn)行時不包含泛型信息,所有的泛型類型映射到同一份字節(jié)碼。
reified generic:泛型類型存在于編譯和運(yùn)行期間,編譯器自動為每一種泛型類型生成類型代碼并編譯進(jìn)二進(jìn)制碼中。
為什么Java是type erasure這是由于泛型是后來(SE5)才加入到Java語言特性的,Java讓編譯器擦除掉關(guān)于泛型類型的信息,這樣使得Java可以向后兼容之前沒有使用泛型的類庫和代碼,因為在字節(jié)碼層面是沒有泛型概念的。
type erasure的本質(zhì)泛型(T) --> 編譯器(type erasure) --> 原始類型(T被Object替換)
泛型(? extends XXX) --> 編譯器(type erasure) --> 原始類型(T被XXX替換)
原始類型指被編譯器擦除了泛型信息后,類型變量在字節(jié)碼中的具體類型。
假如,我們定義一個泛型類Generic是這樣的:
class Generic{ private T obj; public Generic(T o) { obj = o; } public T getObj() { return obj; } }
那么,Java編譯后的字節(jié)碼中Generic相當(dāng)于這樣的:
class Generic { private Object obj; public Generic(Object o) { obj = o; } public Object getObj() { return obj; } }
假如,我們使用Generic類是這樣的:
public static void main(String[] args) { Genericgeneric = new Generic ("hehe..."); String str = generic.getObj(); }
那么,Java編譯后的字節(jié)碼中相當(dāng)于這樣的:
public static void main(String[] args) { Generic generic = new Generic("hehe..."); String str = (String) generic.getObj(); }
所以,所有Generic的泛型類型實質(zhì)是同一個類:
public static void main(String[] args) { Generica = new Generic (111); Generic b = new Generic ("bbb"); System.out.println("a"class: " + a.getClass().getName()); System.out.println("b"class: " + b.getClass().getName()); System.out.println("G"class: " + Generic.class.getName()); System.out.println("a"class == b"class == G"class: " + (a.getClass() == b.getClass() && b.getClass() == Generic.class)); }
上述代碼執(zhí)行結(jié)果:
a"class: generic.Generic b"class: generic.Generic G"class: generic.Generic a"class == b"class == G"class: true
__小結(jié)__:Java的泛型只存在于編譯時期,泛型使編譯器可以在編譯期間對類型進(jìn)行檢查以提高類型安全,減少運(yùn)行時由于對象類型不匹配引發(fā)的異常。
type erasure導(dǎo)致泛型的局限性運(yùn)行時隱含類型轉(zhuǎn)換的開銷類型擦除降低了泛型的泛化性,使得某些重要的上下文環(huán)境中不能使用泛型類型,具有一定的局限性。
使用泛型時,Java編譯器自動幫我們生成了類型轉(zhuǎn)換的代碼,這相對于C++模板來說無疑帶來了額外的性能開銷。
類型參數(shù)不能實例化T obj = new T(); // compile error
T[] objs = new T[10]; // compile error
Generic類型參數(shù)不能進(jìn)行類型查詢(類型查詢在運(yùn)行時,運(yùn)行時類型參數(shù)已被擦除)generic = new Generic [10]; // compile error
Generic不能在靜態(tài)域和靜態(tài)方法中引用類型變量a = new Generic (111); if(a instanceof Generic )// compile error if(a instanceof Generic ) // compile error if(a instanceof Generic) // 僅測試了a是否是Generic,忽略了類型參數(shù)
class Generic{ private static T obj;// compile error public static T func(){...}// compile error }
因為所有泛型類最終映射到同一個原始類型類,而靜態(tài)屬性是類級別的,類和實例共同擁有它的一份存儲,因此一份存儲無法安放多個類型的屬性。靜態(tài)方法也是如此。
重載方法簽名沖突:public boolean equals(T obj) // compile error
public boolean equals(T obj)被擦除類型后變?yōu)?b>public boolean equals(Object obj),與根類Object的public boolean equals(Object obj)簽名一樣,而兩者均不能覆蓋對方,導(dǎo)致編譯期名稱沖突。
一個類不能實現(xiàn)同一個泛型接口的兩種變體:interface IFace() {} class FaceImpParent implements IFace {} class FaceImpChild extends FaceImpParent implements IFace {} // compile error
原因是IFace
class GenericExceptionextends Exception {} // compile error
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/66827.html
摘要:在之后提供了泛型,允許在定義類的時候使用類型作為參數(shù)。泛型廣泛應(yīng)用于各類集合中。本文對其以及其用法進(jìn)行介紹。報錯如下原因是類型擦除機(jī)制,在編譯成文件時候,編譯器并未把和類型信息編譯進(jìn)去。通配符和無界通配符無界通配符可接收任何類型。 在JDK5之后java提供了泛型(Java Genertics),允許在定義類的時候使用類型作為參數(shù)。泛型廣泛應(yīng)用于各類集合中。本文對其以及其用法進(jìn)行介紹。...
摘要:首先,我們來按照泛型的標(biāo)準(zhǔn)重新設(shè)計一下類。注意參數(shù)為而不是泛型。利用形式的通配符,可以實現(xiàn)泛型的向上轉(zhuǎn)型,來看例子。需要注意的是,無法從這樣類型的中取出數(shù)據(jù)。showImg(https://user-gold-cdn.xitu.io/2019/5/17/16ac3bf3eb16160c); 00、故事的起源 二哥,要不我上大學(xué)的時候也學(xué)習(xí)編程吧?有一天,三妹突發(fā)奇想地問我。 你確定要做一名...
摘要:靜態(tài)變量是被泛型類的所有實例所共享的。對于這個類型系統(tǒng),有如下的一些規(guī)則相同類型參數(shù)的泛型類的關(guān)系取決于泛型類自身的繼承體系結(jié)構(gòu)。在代碼中避免泛型類和原始類型的混用。參考泛型類型擦除 Java泛型總結(jié) Java泛型是JDK5引入的一個新特性,允許在定義類和接口的時候使用類型參數(shù)(type parameter)。聲明的類型參數(shù)在使用的時候使用具體的類型來替換。泛型最主要的應(yīng)用是在JDK5...
摘要:問題在遇到有同學(xué)反饋了個問題第一眼的感覺應(yīng)該是泛型擦除和類型推斷導(dǎo)致的但當(dāng)我嘗試去徹底解釋這個問題的時候才發(fā)現(xiàn)關(guān)鍵原因是如果在調(diào)用方法時有那么方法返回的是定義中返回類型經(jīng)過擦除后的結(jié)果具體問題是這個樣子的錯誤不兼容的類型無法轉(zhuǎn)換為猜測 問題 在 v2 遇到有同學(xué)反饋了個問題, 第一眼的感覺應(yīng)該是泛型擦除(Type Erasure)和類型推斷(Type Inference)導(dǎo)致的. 但當(dāng)...
閱讀 3969·2021-11-23 10:09
閱讀 1338·2021-11-23 09:51
閱讀 2939·2021-11-23 09:51
閱讀 1585·2021-09-07 09:59
閱讀 2354·2019-08-30 15:55
閱讀 2292·2019-08-30 15:55
閱讀 2949·2019-08-30 15:52
閱讀 2560·2019-08-26 17:04