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