摘要:泛型類型僅存在于編譯期間,編譯后的字節(jié)碼和運(yùn)行時(shí)不包含泛型信息,所有的泛型類型映射到同一份字節(jié)碼。的本質(zhì)泛型編譯器原始類型被替換泛型編譯器原始類型被替換原始類型指被編譯器擦除了泛型信息后,類型變量在字節(jié)碼中的具體類型。
type erasure & reified generic
Java的泛型不同于C++的模板:Java泛型是"type erasure",C++模板是"reified generic"。
type erasure:泛型類型僅存在于編譯期間,編譯后的字節(jié)碼和運(yùn)行時(shí)不包含泛型信息,所有的泛型類型映射到同一份字節(jié)碼。
reified generic:泛型類型存在于編譯和運(yùn)行期間,編譯器自動(dòng)為每一種泛型類型生成類型代碼并編譯進(jìn)二進(jìn)制碼中。
為什么Java是type erasure這是由于泛型是后來(SE5)才加入到Java語言特性的,Java讓編譯器擦除掉關(guān)于泛型類型的信息,這樣使得Java可以向后兼容之前沒有使用泛型的類庫和代碼,因?yàn)樵谧止?jié)碼層面是沒有泛型概念的。
type erasure的本質(zhì)泛型(T) --> 編譯器(type erasure) --> 原始類型(T被Object替換)
泛型(? extends XXX) --> 編譯器(type erasure) --> 原始類型(T被XXX替換)
原始類型指被編譯器擦除了泛型信息后,類型變量在字節(jié)碼中的具體類型。
假如,我們定義一個(gè)泛型類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的泛型類型實(shí)質(zhì)是同一個(gè)類:
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的泛型只存在于編譯時(shí)期,泛型使編譯器可以在編譯期間對類型進(jìn)行檢查以提高類型安全,減少運(yùn)行時(shí)由于對象類型不匹配引發(fā)的異常。
type erasure導(dǎo)致泛型的局限性運(yùn)行時(shí)隱含類型轉(zhuǎn)換的開銷類型擦除降低了泛型的泛化性,使得某些重要的上下文環(huán)境中不能使用泛型類型,具有一定的局限性。
使用泛型時(shí),Java編譯器自動(dòng)幫我們生成了類型轉(zhuǎn)換的代碼,這相對于C++模板來說無疑帶來了額外的性能開銷。
類型參數(shù)不能實(shí)例化T obj = new T(); // compile error
T[] objs = new T[10]; // compile error
Generic類型參數(shù)不能進(jìn)行類型查詢(類型查詢在運(yùn)行時(shí),運(yùn)行時(shí)類型參數(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 }
因?yàn)樗蟹盒皖愖罱K映射到同一個(gè)原始類型類,而靜態(tài)屬性是類級別的,類和實(shí)例共同擁有它的一份存儲(chǔ),因此一份存儲(chǔ)無法安放多個(gè)類型的屬性。靜態(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)致編譯期名稱沖突。
一個(gè)類不能實(shí)現(xiàn)同一個(gè)泛型接口的兩種變體: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://systransis.cn/yun/66827.html
摘要:在之后提供了泛型,允許在定義類的時(shí)候使用類型作為參數(shù)。泛型廣泛應(yīng)用于各類集合中。本文對其以及其用法進(jìn)行介紹。報(bào)錯(cuò)如下原因是類型擦除機(jī)制,在編譯成文件時(shí)候,編譯器并未把和類型信息編譯進(jìn)去。通配符和無界通配符無界通配符可接收任何類型。 在JDK5之后java提供了泛型(Java Genertics),允許在定義類的時(shí)候使用類型作為參數(shù)。泛型廣泛應(yīng)用于各類集合中。本文對其以及其用法進(jìn)行介紹。...
摘要:首先,我們來按照泛型的標(biāo)準(zhǔn)重新設(shè)計(jì)一下類。注意參數(shù)為而不是泛型。利用形式的通配符,可以實(shí)現(xiàn)泛型的向上轉(zhuǎn)型,來看例子。需要注意的是,無法從這樣類型的中取出數(shù)據(jù)。showImg(https://user-gold-cdn.xitu.io/2019/5/17/16ac3bf3eb16160c); 00、故事的起源 二哥,要不我上大學(xué)的時(shí)候也學(xué)習(xí)編程吧?有一天,三妹突發(fā)奇想地問我。 你確定要做一名...
摘要:泛型的參數(shù)只可以代表類,不能代表個(gè)別對象。生成的字節(jié)代碼中不包含類型信息例如編譯后看到的只是靜態(tài)變量是被泛型類的所有實(shí)例所共享的。對于聲明為的類,訪問其中的靜態(tài)變量的方法仍然是。不管是通過還是創(chuàng)建的對象,都是共享一個(gè)靜態(tài)變量。 Java泛型的參數(shù)只可以代表類,不能代表個(gè)別對象。 由于Java泛型的類型參數(shù)之實(shí)際類型在編譯時(shí)會(huì)被消除,所以無法在運(yùn)行時(shí)得知其類型參數(shù)的類型。 In Jav...
摘要:靜態(tài)變量是被泛型類的所有實(shí)例所共享的。對于這個(gè)類型系統(tǒng),有如下的一些規(guī)則相同類型參數(shù)的泛型類的關(guān)系取決于泛型類自身的繼承體系結(jié)構(gòu)。在代碼中避免泛型類和原始類型的混用。參考泛型類型擦除 Java泛型總結(jié) Java泛型是JDK5引入的一個(gè)新特性,允許在定義類和接口的時(shí)候使用類型參數(shù)(type parameter)。聲明的類型參數(shù)在使用的時(shí)候使用具體的類型來替換。泛型最主要的應(yīng)用是在JDK5...
摘要:問題在遇到有同學(xué)反饋了個(gè)問題第一眼的感覺應(yīng)該是泛型擦除和類型推斷導(dǎo)致的但當(dāng)我嘗試去徹底解釋這個(gè)問題的時(shí)候才發(fā)現(xiàn)關(guān)鍵原因是如果在調(diào)用方法時(shí)有那么方法返回的是定義中返回類型經(jīng)過擦除后的結(jié)果具體問題是這個(gè)樣子的錯(cuò)誤不兼容的類型無法轉(zhuǎn)換為猜測 問題 在 v2 遇到有同學(xué)反饋了個(gè)問題, 第一眼的感覺應(yīng)該是泛型擦除(Type Erasure)和類型推斷(Type Inference)導(dǎo)致的. 但當(dāng)...
閱讀 3998·2021-11-23 10:09
閱讀 1353·2021-11-23 09:51
閱讀 2956·2021-11-23 09:51
閱讀 1605·2021-09-07 09:59
閱讀 2364·2019-08-30 15:55
閱讀 2314·2019-08-30 15:55
閱讀 2963·2019-08-30 15:52
閱讀 2573·2019-08-26 17:04