Java泛型深入理解小總結(jié)

1、何為泛型
首先泛型的本質(zhì)便是類型參數(shù)化,通俗的說就是用一個(gè)變量來表示類型,這個(gè)類型可以是String,Integer等等不確定,表明可接受的類型,原理類似如下代碼
int pattern; //聲明一個(gè)變量未賦值,pattern可以看作是泛型
pattern = 4;
pattern = 5;//4和5就可以看作是String和Integer

泛型的具體形式見泛型類、泛型方法

泛型類形式如下

*泛型方法舉例代碼如下
public <T> void show()
{
operation about T...
}
泛型參數(shù)類型聲明必須在返回類型之前
2、為何要引入泛型,即泛型與Object的優(yōu)勢(shì)
由于泛型可以接受多個(gè)參數(shù),而Object經(jīng)過強(qiáng)制類型轉(zhuǎn)換可以轉(zhuǎn)換為任何類型,既然二者都具有相同的作用,為何還要引進(jìn)泛型呢?
解答:泛型可以把使用Object的錯(cuò)誤提前到編譯后,而不是運(yùn)行后,提升安全性。以下用帶泛型的ArrayList和不帶泛型的Arraylist舉例說明
代碼1:
ArrayList al = new ArrayList();al.add("hello");
al.add(4);//自動(dòng)裝箱
String s1 = (String)al.get(0);
String s2 = (String)al.get(1);//在編譯時(shí)沒問題,但在運(yùn)行時(shí)出現(xiàn)問題

首先聲明無泛型的ArrayList時(shí),其默認(rèn)的原始類型是Object數(shù)組,既然為Object類型,就可以接受任意數(shù)據(jù)的賦值,因此編譯時(shí)沒有問題,但是在運(yùn)行時(shí),Integer強(qiáng)轉(zhuǎn)成String,肯定會(huì)出現(xiàn)ClassCastException.因此泛型的引入增強(qiáng)了安全性,把類轉(zhuǎn)換異常提前到了編譯時(shí)期。
3、類型擦除和原始類型
  類型擦除的由來
在JAVA的虛擬機(jī)中并不存在泛型,泛型只是為了完善java體系,增加程序員編程的便捷性以及安全性而創(chuàng)建的一種機(jī)制,在JAVA虛擬機(jī)中對(duì)應(yīng)泛型的都是確定的類型,在編寫泛型代碼后,java虛擬中會(huì)把這些泛型參數(shù)類型都擦除,用相應(yīng)的確定類型來代替,代替的這一動(dòng)作叫做類型擦除,而用于替代的類型稱為原始類型,在類型擦除過程中,一般使用第一個(gè)限定的類型來替換,若無限定則使用Object.

對(duì)泛型類的翻譯,泛型類(不帶泛型限定)代碼:

虛擬機(jī)進(jìn)行翻譯后的原始類型:
泛型類(帶泛型限定)代碼: 
虛擬機(jī)進(jìn)行翻譯后的原始類型:

泛型方法的翻譯


由于TestDemo繼承Test<String>,但是Test在類型擦除后還有一個(gè)public void Show(Object t),這和那個(gè)show(String t)出現(xiàn)重載,但是本意卻是沒有show(Object t)的,
因此在虛擬機(jī)翻譯泛型方法中,引入了橋方法,及在類型擦除后的show(Object t)中調(diào)用另一個(gè)方法,代碼如下:
public void show(Object t){
show((String) t);
}
4、泛型限定
  泛型限定是通過?(通配符)來實(shí)現(xiàn)的,表示可以接受任意類型,那一定有人有疑問,那?和T(二者單獨(dú)使用時(shí))有啥區(qū)別了,其實(shí)區(qū)別也不是很大,僅僅在對(duì)參數(shù)類型的使用上。例如:

? extends SomeClass 這種限定,說明的是只能接收SomeClass及其子類類型,所謂的“上限”
  ? super SomeClass 這種限定,說明只能接收SomeClass及其父類類型,所謂的“下限”
一下舉例? extends SomeClass說明一下這類限定的一種應(yīng)用方式
由于泛型參數(shù)類型可以表示任意類型的類類型,若T要引用compareTo方法,如何保證在T類中定義了compareTo方法呢?利用如下代碼:
public <T extends Comparable> shwo(T a, T b){
int num = a.compareTo(b);
}
此處用于限定T類型繼承自Comparable,因?yàn)門類型可以調(diào)用compareTo方法。
  可以有多個(gè)類型限定,例如:
<T extends Comparable & Serializable>

這種書寫方式為何把comparable寫在前邊?因?yàn)橛捎陬愋筒脸膯栴},原始類型是由Comparable替換的,因此寫在前邊的是類中存在此類型的泛型方法放在前邊,避免調(diào)用方法時(shí)類型的強(qiáng)制轉(zhuǎn)換,提高效率。

關(guān)于泛型類型限定的“繼承”誤區(qū)
總有些人誤把類型的限定當(dāng)作繼承,比如:
//類型是這樣的
<Student extends Person>
//然后出現(xiàn)此類錯(cuò)誤
ArrayList<Person> al = new ArrayList<Student>();
此處的<Person>, <Student>作為泛型的意思是ArrayList容器的接收類型,用一個(gè)簡(jiǎn)單的例子來說明
ArrayList是一個(gè)大型養(yǎng)殖場(chǎng),<Person>表明的是他能夠接收動(dòng)物,而上邊的new語句生成的是一個(gè)只能夠接收豬的養(yǎng)殖場(chǎng)(ArrayList<Student>),即把一個(gè)大型養(yǎng)殖場(chǎng)建造成了一個(gè)養(yǎng)豬場(chǎng),若是繼承的大型養(yǎng)殖場(chǎng)肯定是還能接受狗、羊....的,但是現(xiàn)在建造成了養(yǎng)豬場(chǎng),那還能接受別的動(dòng)物么?所以這肯定是錯(cuò)誤的用法!簡(jiǎn)而言之,泛型new時(shí)兩邊的類型參數(shù)必須一致。
5、泛型的一些基本規(guī)則約束
  泛型的類型參數(shù)必須為類的引用,不能用基本類型(int, short, long, byte, float, double, char, boolean)
  泛型是類型的參數(shù)化,在使用時(shí)可以用作不同類型(此處在說泛型類時(shí)會(huì)詳細(xì)說明)
  泛型的類型參數(shù)可以有多個(gè),代碼舉例如下:
public <T, E> void show(){ coding operation..... }

泛型可以使用extends, super, ?(通配符)來對(duì)類型參數(shù)進(jìn)行限定
  由于類型擦除,運(yùn)行時(shí)類型查詢只適用于原始類型,比如instanceof、getClass()、強(qiáng)制類型轉(zhuǎn)換,a instanceof (Pair<Employe>),在類型擦除后便是 a instanceof Pair,因此以上運(yùn)行的一些操作在虛擬機(jī)中操作都是對(duì)原始類型進(jìn)行操作,無論寫的多么虛幻,都逃不出類型擦除,因?yàn)樵谔摂M機(jī)種并不存在泛型。
  不能創(chuàng)建參數(shù)化類型的數(shù)組

例如寫如下代碼:
由于Object可以接收任何類型,在里邊存入 new Pari<Employe>時(shí),沒有任何問題,但是當(dāng)取出的時(shí)候會(huì)出現(xiàn)ClassCastException,因此不能創(chuàng)建參數(shù)化類型數(shù)組。
  不能實(shí)例化類型變量,及不能出現(xiàn)以下的類似代碼
T t = new T();//或T.Class

因?yàn)樵陬愋筒脸螅闶荗bject t = new Object();與用意不符合,即本意肯定不是要調(diào)用Object.
  不能再靜態(tài)域或方法中出現(xiàn)參數(shù)類型

例如如下錯(cuò)誤代碼:
首先方法是一個(gè)返回類型為T的普通方法,而非泛型方法,這和在靜態(tài)方法中使用非靜態(tài)參數(shù)是一樣的,靜態(tài)方法是先于對(duì)象而存在內(nèi)存中的,因此在編譯的時(shí)候,T的類型無法確定,一定會(huì)出現(xiàn)“Cannot make a static reference to a non_static reference”這樣類似的錯(cuò)誤。
但是這樣的代碼就是正確的
class Test<T>{public static <T> T show() { action }}
因?yàn)榇颂幍撵o態(tài)方法是泛型方法,可以使用.
  不能拋出或捕獲泛型類的實(shí)例
    +不能拋出不能捕獲泛型類對(duì)象
    +泛型類不能擴(kuò)展Throwable,注意是類不能繼承Throwable,類型參數(shù)的限定還是可以的。
    +catch子句不能使用類型變量,如下代碼:

類型擦除后的沖突注意,例如:

此處的錯(cuò)誤的原因不能存在同一個(gè)方法,在類型擦除后,Pair的方法為,public boolean equals(Object value),這與從Object.class中繼承下來的equals(Object obj)沖突。
  一個(gè)類不能成為兩個(gè)接口類型的子類,而這兩個(gè)接口是同一接口的不同參數(shù)化。
例如:
class Calendar implements coparable<Calendar>{}class GregorianCalendar extends Calendar implements Comparable<GregorianCalendar>{} //error

當(dāng)類型擦除后,Calendar實(shí)現(xiàn)的是Comparable,而GregorianCalendar繼承了Calendar,又去實(shí)現(xiàn)Comparable,必然出錯(cuò)!
———————————————————————————————————————————————————————————————————————————————
先總結(jié)到此處。

最后編輯于
?著作權(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),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 泛型是Java 1.5引入的新特性。泛型的本質(zhì)是參數(shù)化類型,這種參數(shù)類型可以用在類、變量、接口和方法的創(chuàng)建中,分別...
    何時(shí)不晚閱讀 3,115評(píng)論 0 2
  • 引言:泛型一直是困擾自己的一個(gè)難題,但是泛型有時(shí)一個(gè)面試時(shí)老生常談的問題;今天作者就通過查閱相關(guān)資料簡(jiǎn)單談?wù)勛约簩?duì)...
    cp_insist閱讀 1,932評(píng)論 0 4
  • 在之前的文章中分析過了多態(tài),可以知道多態(tài)本身是一種泛化機(jī)制,它通過基類或者接口來設(shè)計(jì),使程序擁有一定的靈活性,但是...
    _小二_閱讀 752評(píng)論 0 0
  • [TOC] 深入理解 Java 泛型 概述 泛型的本質(zhì)是參數(shù)化類型,通常用于輸入?yún)?shù)、存儲(chǔ)類型不確定的場(chǎng)景。相比于...
    albon閱讀 5,785評(píng)論 0 7
  • Why ——引入泛型機(jī)制的原因 假如我們想要實(shí)現(xiàn)一個(gè)String數(shù)組,并且要求它可以動(dòng)態(tài)改變大小,這時(shí)我們都會(huì)想到...
    absfree閱讀 5,272評(píng)論 1 6

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