Java語(yǔ)法關(guān)于泛型與類型擦除的分析
泛型與類型擦除
泛型,JDK 1.5新特性,本質(zhì)是參數(shù)化類型(Parametersized Type) 的應(yīng)用,即所操作的數(shù)據(jù)類型被指定為一個(gè)參數(shù)。這種參數(shù)類型可用在:
- 類
- 接口
- 方法
的創(chuàng)建中, 分別稱為:
- 泛型類
- 泛型接口
- 泛型方法
在Java還沒(méi)有泛型的版本時(shí)。只能通過(guò):
- Object 是所有類型的父類
- 類型強(qiáng)制轉(zhuǎn)換
兩個(gè)特性協(xié)作實(shí)現(xiàn)類型泛化。例如,在哈希表的存取中,JDK 1.5之前使用HashMap的get() 方法,返回值就是個(gè)Object。由于Java語(yǔ)言里面所有的類型都維承于java.lang.Object
,所以O(shè)bject轉(zhuǎn)型成任何對(duì)象都有可能。但也因?yàn)橛袩o(wú)限的可能性,就只有程序員和運(yùn)行期的虛擬機(jī)才知道這個(gè)Objet到底是個(gè)什么類型的對(duì)象。
編譯期間,編譯器無(wú)法檢查該Object的強(qiáng)制轉(zhuǎn)型是否成功。若僅僅依賴程序員去保障正確性,許多ClassCastException的風(fēng)險(xiǎn)就會(huì)延遲到程序運(yùn)行期。
Java語(yǔ)言中的泛型則不一樣,它只在程序源碼中存在,在編譯后的字節(jié)碼文件中,就已經(jīng)替換為原來(lái)的原生類型(Raw Type) ,并在相應(yīng)地方插入強(qiáng)制轉(zhuǎn)換代碼。
因此,對(duì)運(yùn)行期的Java來(lái)說(shuō)Araylist<int>
、Aralist<String>
是同一個(gè)類。所以泛型是Java語(yǔ)言的一顆語(yǔ)法糖Java稱為類型擦除,基于這種方法實(shí)現(xiàn)的泛型稱為偽泛型。
- 泛型擦除前的例子
把這段Java代碼編譯成Class文件,然后再用字節(jié)碼反編譯后,將會(huì)發(fā)現(xiàn)泛型都不見了,又變回了Java泛型出現(xiàn)之前的寫法,泛型類型都變回了原類型。如:
通過(guò)擦除實(shí)現(xiàn)泛型,喪失了一些泛型思想應(yīng)有的優(yōu)雅
- 當(dāng)泛型遇見重載1
不能被編譯的,因?yàn)閰?shù)List<Integer>
和List<String>
編譯之后都被擦除了。變成了一樣的原生類型List<E>
,擦除動(dòng)作導(dǎo)致這兩種方法的特征簽名變得一模一樣。初步看來(lái),無(wú)法重載的原因已經(jīng)找到了,但真的就如此嗎? 只能說(shuō),泛型擦除成相同的原生類型只是無(wú)法重載的部分原因當(dāng)
- 泛型遇見置載2
由于Java泛型的引入,各種場(chǎng)景(虛擬機(jī)解析、反射等)下的方法調(diào)用都可能對(duì)原有基礎(chǔ)產(chǎn)生影響,如在泛型類中如何獲取傳入的參數(shù)化類型等。因此,JCP組織對(duì)虛擬機(jī)規(guī)范做出了相應(yīng)的修改,引入了諸如Signature
、LocalVariableTypeTable
等新的屬性用于解決伴隨泛型而來(lái)的參數(shù)類型的識(shí)別問(wèn)題,Signature 是其中最重要的一項(xiàng)屬性,它的作用就是存儲(chǔ)一個(gè)方法在字節(jié)碼層面的特征簽名,這個(gè)屬性中保存的參數(shù)類型并不是原生類型,而是包括了參數(shù)化類型的信息。修改后的虛擬機(jī)規(guī)范要求所有能識(shí)別49.0以上版本的Class文件的虛擬機(jī)都要能正確地識(shí)別Signature參數(shù)。
從Signature屬性的出現(xiàn)我們還可以得出結(jié)論,所謂的擦除,僅僅是對(duì)方法的Code屬性中的字節(jié)碼進(jìn)行擦除,實(shí)際上元數(shù)據(jù)還是保留了泛型信息,這也是我們能通過(guò)反射取得參數(shù)化類型的根本依據(jù)。
- 自動(dòng)裝箱: 拆箱與遍歷循環(huán)
- 自動(dòng)裝箱: 拆箱與遍歷循環(huán)編譯后
遍歷循環(huán)則把代碼還原成了迭代器的實(shí)現(xiàn),這也是為何遍歷循環(huán)需要被遍歷的類實(shí)現(xiàn)Iterable接口的原因。最后再看看變長(zhǎng)參數(shù),它在調(diào)用的時(shí)候變成了一個(gè)數(shù)組類型的參數(shù),在變長(zhǎng)參數(shù)出現(xiàn)之前,程序員就是使用數(shù)組來(lái)完成類似功能的。
到此這篇關(guān)于Java語(yǔ)法關(guān)于泛型與類型擦除的分析的文章就介紹到這了,更多相關(guān)Java 泛型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot+Nacos+Kafka微服務(wù)流編排的簡(jiǎn)單實(shí)現(xiàn)
本文主要介紹了SpringBoot+Nacos+Kafka微服務(wù)流編排的簡(jiǎn)單實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08Java實(shí)現(xiàn)注冊(cè)郵箱激活賬戶實(shí)例代碼
本篇文章主要介紹了Java實(shí)現(xiàn)郵箱激活賬戶實(shí)例代碼,這里整理了詳細(xì)的代碼,具有一定的參考價(jià)值,有需要的小伙伴可以參考下。2017-07-07java kafka寫入數(shù)據(jù)到HDFS問(wèn)題
這篇文章主要介紹了java kafka寫入數(shù)據(jù)到HDFS問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08Java使用默認(rèn)瀏覽器打開指定URL的方法(二種方法)
Java使用默認(rèn)瀏覽器打開指定URL。2013-10-10java向數(shù)據(jù)庫(kù)插入數(shù)據(jù)顯示亂碼的幾種問(wèn)題解決
這篇文章主要給大家介紹了關(guān)于java向數(shù)據(jù)庫(kù)插入數(shù)據(jù)顯示亂碼問(wèn)題的解決方案,文章分別羅列了前臺(tái)亂碼的問(wèn)題、前臺(tái)先后臺(tái)插入數(shù)據(jù)后臺(tái)接收到的數(shù)據(jù)是亂碼以及后臺(tái)向數(shù)據(jù)庫(kù)插入數(shù)據(jù)是亂碼等幾種情況,需要的朋友可以參考下2021-11-11