java 泛型精解

其實(shí)關(guān)于這塊知識(shí)大概兩年以前就有了個(gè)比較全的了解了吧,重新整理一下用自己的話寫出來又是一次加深理解的過程。下面我大概會(huì)分三個(gè)方面去講泛型,1、泛型的主要相關(guān)特性 2、怎么用泛型 3、泛型總結(jié)

1、泛型的主要相關(guān)特性

背景介紹:

Java泛型(generics)是JDK 5中引入的一個(gè)新特性,允許在定義類和接口的時(shí)候使用類型參數(shù)(type parameter)。聲明的類型參數(shù)在使用時(shí)用具體的類型來替換。泛型最主要的應(yīng)用是在JDK 5中的新集合類框架中。對(duì)于泛型概念的引入,開發(fā)社區(qū)的觀點(diǎn)是褒貶不一。從好的方面來說,泛型的引入可以解決之前的集合類框架在使用過程中通常會(huì)出現(xiàn)的運(yùn)行時(shí)刻類型錯(cuò)誤,因?yàn)榫幾g器可以在編譯時(shí)刻就發(fā)現(xiàn)很多明顯的錯(cuò)誤。而從不好的地方來說,為了保證與舊有版本的兼容性,Java泛型的實(shí)現(xiàn)上存在著一些不夠優(yōu)雅的地方。當(dāng)然這也是任何有歷史的編程語言所需要承擔(dān)的歷史包袱。后續(xù)的版本更新會(huì)為早期的設(shè)計(jì)缺陷所累。

a、類型擦除

正確理解泛型概念的首要前提是理解類型擦除(type erasure)。 Java中的泛型基本上都是在編譯器這個(gè)層次來實(shí)現(xiàn)的。在生成的Java字節(jié)代碼中是不包含泛型中的類型信息的。使用泛型的時(shí)候加上的類型參數(shù),會(huì)被編譯器在編譯的時(shí)候去掉。這個(gè)過程就稱為類型擦除。還是上例子吧,如下:


泛型擦除導(dǎo)致編譯不通過

按照我們對(duì)于重載的理解,方法參數(shù)類型不一樣應(yīng)該是可以定義的啊,這個(gè)理論一直是成立的。主要原因是在于泛型是在編譯的時(shí)候類型會(huì)擦除,這樣兩個(gè)方法的參數(shù)類型都是List,是不帶參數(shù)的噢。所以重載不通過導(dǎo)致編譯不通過。

b、泛型在初始化、實(shí)例化的時(shí)候需要知道確切的類型

泛型在沒有申明具體的類型的時(shí)候是不能進(jìn)行實(shí)例化,因?yàn)樗诖藭r(shí)只是一個(gè)代號(hào),換句話說我創(chuàng)建一個(gè)對(duì)象的過程要經(jīng)歷,加載、連接、初始化、實(shí)例化。我連你的基本信息都不知道我怎么進(jìn)行下去啊,上例子,如下:


泛型不知道具體類型初始化編譯不通過

這種情況下new T()編譯失敗。

c、泛型和子類型

我們知道在java中存在 父類 ?a = new 子類(); 這種寫法是成立的而且是一個(gè)比較好的寫法。但是List<父類> list = new ArrayList<子類>(); 這種寫法會(huì)成立嗎,事實(shí)是沒有成立編譯會(huì)報(bào)錯(cuò),上例子:


泛型和子類型轉(zhuǎn)換關(guān)系

為什么會(huì)這樣呢,應(yīng)該這么理解如果這種寫法成立的話,那我fruits就可以add ?Child2、Child3等其他子類了。

到時(shí)候我從fruits里面取出來集合里面的元素的時(shí)候我應(yīng)該轉(zhuǎn)換成Child、Child2、Child3 ??? 編譯器也不知道啊。

d、泛型通配符

我想在通配符這個(gè)點(diǎn)我會(huì)多講一點(diǎn)。

d1、通配符?

這里使用了通配符?指定可以使用任何類型的集合作為參數(shù)。讀取的元素使用了Object類型來表示,這是安全的,因?yàn)樗械念惗际荗bject的子類。這里就又出現(xiàn)了另外一個(gè)問題,如下代碼所示,如果試圖往使用通配符?的集合中加入對(duì)象,就會(huì)在編譯時(shí)出現(xiàn)錯(cuò)誤。需要注意的是,這里不管加入什么類型的對(duì)象都會(huì)出錯(cuò)。這是因?yàn)橥ㄅ浞??表示該集合存?chǔ)的元素類型未知,可以是任何類型。往集合中加入元素需要是一個(gè)未知元素類型的子類型,正因?yàn)樵摷洗鎯?chǔ)的元素類型未知,所以我們沒法向該集合中添加任何元素。唯一的例外是null,因?yàn)閚ull是所有類型的子類型,所以盡管元素類型不知道,但是null一定是它的子類型。另一方面,我們可以從List lists中獲取對(duì)象,雖然不知道List中存儲(chǔ)的是什么類型,但是可以肯定的是存儲(chǔ)的類型一定是Object的子類型,所以可以用Object類型來獲取值。如for(Object obj: lists),這是合法的。

還是上代碼:


通配符?樣例代碼

d2、?extends通配符

其實(shí)這個(gè)也好理解,可以理解為某個(gè)接口或者某個(gè)抽象類的所有實(shí)現(xiàn)類,上例子:


?extends Serializable使用

List<? extends Serializable> 中存放的是所有的Serializable的實(shí)現(xiàn)類,如可能是String、Integer等

我們?cè)谌〕鰜淼臅r(shí)候就可以轉(zhuǎn)換成Serializable ,但是我們還是不能往里面add元素原因跟上面通配符 ?一樣

d3、?super通配符

這里還有一種邊界通配符為?super,可以表示當(dāng)前類或者當(dāng)前類的父類,還是上例子吧:

?super通配符使用

e、泛型的推斷

自Java SE 7起, 你可以使用一個(gè)空的類型參數(shù)集合 (<>)代替構(gòu)造器的參數(shù)化類型:Map<String, List> myMap = new HashMap<>();注意:想要在泛型類初始化期間利用自動(dòng)類型推斷。

2、怎么用泛型

上面主要介紹了一些泛型的主要特性吧,下面我還是想說說怎么使用泛型吧。

泛型用自己的話來說就是“參數(shù)化類型”,在各種實(shí)體類型的基礎(chǔ)上抽象出一個(gè)虛擬的類型,你可以叫A、B、C、T等。

具體的使用可以有兩種比較常見的表現(xiàn)形式,類泛型 、方法泛型

a、類泛型

從字面上理解為你定義的泛型是整個(gè)類通用的或者是類里面所有的泛型類型就引用類上的自己方法上不額外定義,例子如下:


類泛型定義
類泛型實(shí)現(xiàn)

從上面可以看出類中定義了請(qǐng)求類型為Request返回類型為Response這個(gè)為了可讀性強(qiáng)一點(diǎn)這么定義,在process抽象方法中直接用Request,Response來表示方法所需要的類型。

在實(shí)現(xiàn)類中就可以用具體的String、Integer代替接口中申明的泛型類型。

b、方法泛型

方法泛型我感覺就沒類泛型那么抽象性高,可以為每一個(gè)方法來獨(dú)自定義自己的類型了,上例子:

方法泛型實(shí)現(xiàn)


如上是一個(gè)簡單的將List 里面的實(shí)體用某個(gè)字段作為key轉(zhuǎn)換到Map中,中間的轉(zhuǎn)換過程TODO.

方法上應(yīng)用了K,V兩個(gè)類型,但是這兩個(gè)類型是需要申明定義的,所以在方法修飾符后面要自定義一下類型,如果不定義<K,V>是要編譯出錯(cuò)的。

3、泛型總結(jié)

上面1、2部分介紹了泛型的一些主要特性和常用用法以后,我們對(duì)于泛型的認(rèn)識(shí)應(yīng)該是比較清晰的,所有的哪怕是泛型的復(fù)雜應(yīng)用都是從上面講的一些演變過來了,其實(shí)挺簡單的。什么時(shí)候用泛型這個(gè)需要自己去思考?總之我覺得能夠抽象出一個(gè)統(tǒng)一的類型就可以用。。。

3 Q very much!!!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • object 變量可指向任何類的實(shí)例,這讓你能夠創(chuàng)建可對(duì)任何數(shù)據(jù)類型進(jìn)程處理的類。然而,這種方法存在幾個(gè)嚴(yán)重的問題...
    CarlDonitz閱讀 1,021評(píng)論 0 5
  • 開發(fā)人員在使用泛型的時(shí)候,很容易根據(jù)自己的直覺而犯一些錯(cuò)誤。比如一個(gè)方法如果接收List作為形式參數(shù),那么如果嘗試...
    時(shí)待吾閱讀 1,127評(píng)論 0 3
  • 前言 人生苦多,快來 Kotlin ,快速學(xué)習(xí)Kotlin! 什么是Kotlin? Kotlin 是種靜態(tài)類型編程...
    任半生囂狂閱讀 26,703評(píng)論 9 118
  • 上午回姥娘家。小姑娘自己選擇要穿那件粉色的長袖公主裙。想到接下來幾乎所以的日子都要穿那身肥大,沒有性別區(qū)分的校服,...
    江漢漁歌閱讀 142評(píng)論 0 0
  • 我們的這座小城雖然地方不大,書店卻不少,單單新華書店就有兩個(gè),其他知名、不知名的小書店更是多如牛毛。當(dāng)然,若論藏書...
    辰辰的爸爸閱讀 323評(píng)論 4 0

友情鏈接更多精彩內(nèi)容