?????對(duì)于我們java中的泛型,可能很多人知道怎么使用并且使用的還不錯(cuò),但是我認(rèn)為想要恰到好處的使用泛型偷俭,還是需要深入的了解一下它的各種概念和內(nèi)部原理。本文將盡可能的囊括java泛型中的重要的概念缰盏。主要內(nèi)容如下:
- 泛型的定義及為什么要使用泛型
- 定義一個(gè)簡(jiǎn)單的泛型類
- 定義一個(gè)簡(jiǎn)單的泛型方法
- 類型參數(shù)的限定
- 泛型內(nèi)部實(shí)現(xiàn)的基本原理
- 泛型通配符(難點(diǎn))
- 泛型的其他實(shí)現(xiàn)細(xì)節(jié)
一涌萤、何謂泛型
?????泛型程序設(shè)計(jì)意味著編寫的代碼可以被不同中類型的對(duì)象重用。例如:MyList<T>,MyList<Integer>是一種類型口猜,MyList<String>也是一種類型负溪,但是使用的代碼塊都是MyList<T>,這也就是java中引入泛型的一種原因:可以增強(qiáng)代碼的復(fù)用性济炎,當(dāng)然這種限定死類型的方式也會(huì)使得代碼的安全性和可讀性更高川抡。
二、一個(gè)簡(jiǎn)單的泛型類
先看一個(gè)完整的泛型類:
/*一個(gè)簡(jiǎn)單的泛型類的聲明如下*/
public class Pair<T> {
private T a;
private T b;
public Pair(T a, T b){
this.a = a;
this.b = b;
}
}
?????由此可以看出來(lái)须尚,泛型類型和普通類型的區(qū)別主要在于:類名之后多了個(gè)<T>崖堤,并且實(shí)例域類型可以不是具體的類型而是不確定的T類型。其中耐床,我們管T叫做類型變量密幔,類型變量一般使用大寫字母表示并且很短(在java中使用E表示集合的元素類型,K和V分別表示關(guān)鍵字和值的類型)撩轰。
使用具體的類型來(lái)替換類型變量的過程我們叫做實(shí)例化泛型類型胯甩。例如:Pair<Integer>,<Double>等昧廷。這其中需要注意的是:java中的9中基本類型是不能作為類型變量的,也就是:Pair<int>,是會(huì)不允許的偎箫。當(dāng)然木柬,聲明一個(gè)泛型類時(shí),不局限于一個(gè)類型變量镜廉,可以由多個(gè)類型變量弄诲,例如:
/*聲明兩個(gè)類型變量也是可以的*/
public class Pair<T,U> {
private T a;
private U b;
public Pair(T a, U b){
this.a = a;
this.b = b;
}
}
//Pair<String,Integer> p new Pair<>("abc",12);
//創(chuàng)建泛型類實(shí)例變量的時(shí)候,可以省略類型變量娇唯,編譯器可以推測(cè)出來(lái)
三、一個(gè)簡(jiǎn)單的泛型方法
?????怎么定義泛型類寂玲,我們已經(jīng)介紹過了塔插,接下來(lái)我們一起看看泛型方法是如何定義和調(diào)用的。
/*泛型類中定義了一個(gè)泛型方法*/
public class Pair<T> {
//聲明一個(gè)泛型方法
public <T> T getA(T c){
return c;
}
}
/*main函數(shù)中調(diào)用泛型方法*/
public class Test2 {
public static void main(String[] args){
Pair<Integer> p = new Pair<Integer>(1,2);
//調(diào)用泛型方法
System.out.println(p.<Integer>show(10));
}
}
?????我們可以看到拓哟,聲明一個(gè)泛型方法:public <T > T getA(T c)想许,<T >放在返回值前面,修飾符后面断序,T表示返回類型流纹。泛型方法的調(diào)用:p.<Integer>show(10),在方法名前面放置類型變量,當(dāng)然也可以選擇省略违诗,當(dāng)編譯器沒有足夠的信息推測(cè)出來(lái)時(shí)就會(huì)報(bào)錯(cuò)漱凝,那時(shí)你再添加也不遲(但是,如果你能減輕計(jì)算機(jī)的工作的話诸迟,想必是可以提高效率的)
?????小結(jié)一下茸炒,泛型類和泛型方法。泛型類中可以聲明泛型方法也可以聲明普通方法阵苇,泛型方法可以出現(xiàn)在泛型類中也可以出現(xiàn)在普通類中壁公,也就是它們之間并沒有什么約束關(guān)系器瘪。
四拥褂、類型變量的限定
前面我們已經(jīng)知道了什么是類型變量,我們看一段代碼:
public class Pair<T> {
public static <T> int myCompare(T a,T b){
return a.compareTo(b);//此處編譯不通過
}
}
?????我們知道男翰,如果想要使用compareTo方法快耿,就要實(shí)現(xiàn)Comparable接口囊陡,或者繼承實(shí)現(xiàn)了此接口的類。此處想要使得程序正確润努,有兩種辦法关斜。第一種:使類繼承Comparable接口并且實(shí)現(xiàn)compareTo方法。第二種:就是使用類型變量限定铺浇。如下:
/*限定變量類型*/
public class Pair<T> {
public static <T extends Comparable> int myCompare(T a,T b){
return a.compareTo(b);
}
}
?????細(xì)心的同學(xué)可能已經(jīng)發(fā)現(xiàn)痢畜,相比于原來(lái)的方法,就是使類型變量繼承與Comparable接口。原來(lái)的<T >變成了<T extends Comparable>丁稀,表示:原來(lái)的T可以是任意類型的吼拥,而現(xiàn)在的T被限制必須實(shí)現(xiàn)了Comparable 接口,就是說(shuō)线衫,凡是使用此泛型的類都是直接或者間接繼承了Comparable 接口并實(shí)現(xiàn)其中方法的凿可。所以,一旦我們將T限定了授账,就不用考慮實(shí)現(xiàn)Comparable 接口的事情了枯跑,程序的封裝性更強(qiáng)了。
?????對(duì)類型變量的限定可以由多個(gè)限定白热,它們之間使用&分隔敛助,而使用逗號(hào)分隔類型變量∥萑罚看個(gè)例子:
<T extends Comparable> //一個(gè)類型變量的一個(gè)類型限定
<T extends Comparable & Serializable> //一個(gè)類型變量的兩個(gè)類型限定
<T extends Comparable纳击,U extends Serializable>//兩個(gè)類型變量的類型限定
五、泛型實(shí)現(xiàn)的基本原理
?????討論了這么多的泛型方法攻臀,泛型類以及各種使用技巧焕数,接下來(lái),我們一起看看虛擬機(jī)實(shí)際執(zhí)行時(shí)是怎么對(duì)待我們的泛型的刨啸。我們都知道java中有編譯器和虛擬機(jī)堡赔,但實(shí)際上我們的泛型在這兩者看來(lái)是不一樣的,也就是說(shuō)呜投,虛擬機(jī)是不認(rèn)識(shí)泛型的加匈,而只有我們強(qiáng)大的編譯器是認(rèn)識(shí)泛型的。那他們是怎么實(shí)現(xiàn)統(tǒng)一的呢仑荐?接下來(lái)我們?cè)敿?xì)來(lái)看雕拼。
?????在java中,無(wú)論何時(shí)定義了一個(gè)泛型粘招,它都會(huì)自動(dòng)生成一個(gè)相應(yīng)的原始類型啥寇。我們叫這個(gè)過程為:類型擦除。例如下面的代碼:
/*這是一段泛型類的代碼*/
public class Pair<T> {
private T a;
private T b;
public T getA(){
return this.a;
}
public T getB(){
return this.b;
}
}
經(jīng)過類型擦除之后生成原始類型:
public class Pair{
private Object a;
private Object b;
public Object getA(){
return this.a;
}
public Object getB(){
return this.b;
}
}
?????經(jīng)過對(duì)比洒扎,我們可以得出結(jié)論:去除了泛型的標(biāo)志性符號(hào)<>并且所有的T類型都被替換成Object類型了辑甜。難道我們的類型擦除就是將所有的未知類型轉(zhuǎn)換為Object類型嗎?當(dāng)然不是袍冷,類型擦除是有規(guī)則的而不是一味的將未知類型T轉(zhuǎn)換成Object類型的磷醋。
?????對(duì)于有限定的類型變量就將用類型變量的第一個(gè)限定類型替換。如:Pair<T extends Comparable & Serializable>胡诗,就會(huì)選擇用Comparable替換所有的T并去除修飾在類后面的泛型符號(hào)邓线,生成原始類型淌友。
?????對(duì)于沒有限定類型的類型變量就默認(rèn)使用Object替換類型變量。例如:Pair<T>就會(huì)使用Object替換所有的T類型變量骇陈。
?????最后小結(jié)一下震庭,類型擦除針對(duì)是否有類型限定類型,根據(jù)不同的狀況進(jìn)行替換生成相應(yīng)的原始類型供jvm調(diào)用你雌。
未完器联,待續(xù)。婿崭。拨拓。。