今天記錄一下Java中的泛型,畢竟大家在項目中經(jīng)常用到或者看到過。
參考:http://www.itdecent.cn/p/95f349258afb
1.什么是泛型
泛型是Java SE 1.5的新特性,泛型的本質(zhì)是參數(shù)化類型,也就是說所操作的數(shù)據(jù)類型被指定為一個參數(shù),Java語言引入泛型的好處是安全簡單
2.泛型的特性
在Java SE 1.5之前,沒有泛型的下,通過對類型Object的引用來實現(xiàn)參數(shù)的“任意化”,“任意化”帶來的缺點是要做顯式的強制類型轉(zhuǎn)換而這種轉(zhuǎn)換是要求開發(fā)者對實際參數(shù)類型預知的情況下進行的。對于強制類型轉(zhuǎn)換錯誤的情況,編譯器在編譯期間可能不提示錯誤,在運行的時候才出現(xiàn)異常,這是一個安全隱患。泛型的好處是在編譯的時候檢查類型安全,并且所有的強制轉(zhuǎn)換都是自動和隱式的,可以提高代碼的重用率。
拿我們常用的List集合舉個例子:
List mList =new LinkedList();
mList.add("aaa");
int a = (int) mList.get(0);
不用說這樣一運行肯定會報一個類型不能轉(zhuǎn)換的錯誤。注意雖然不正確但編譯器沒有發(fā)現(xiàn),運行時才會報錯,那我們試試加泛型的。

其實我們常用的集合就是加了泛型的,只不過大家可能不在意。
總結(jié):
Object的參數(shù)"任意化"在編譯期間不能發(fā)現(xiàn)錯誤,運行時可能報錯,是個安全隱患,而泛型可以在編譯期間就可以檢查類型安全。
3.常見的泛型分類
泛型有三種分類:泛型類、泛型接口、泛型方法
3.1泛型類
泛型類的定義方式:
public class generic<泛型通配符>{
private 泛型通配符 genericClass;
//泛型構(gòu)造方法形參 parameter的類型也為T,T的類型由外部指定
public Generic(T parameter) {
this.genericClass = parameter;
}
}
這個泛型通配符可以隨意取值:比如A,B,C,D.(注意得是大寫)但我們通常都取?、K、V各自有不同的含義:
- ?:表示不確定的java類型
- T:(type) 表示具體的一個java類型
- K V (key value) 分別代表java鍵值中的Key Value
- E: (element) 代表Element
我們就以K,V這種的通配符定義一個泛型類,代碼如下:
public interface GenericInter<K,V> {
public K getKey();
public V getValue();
}
public class GenericClass<K,V> extends GenericInter{
public K key;
public V value;
public GenericClass(K key, V value) {
this.key = key;
this.value = value;
}
@Override
public Object getKey() {
return key;
}
@Override
public Object getValue() {
return value;
}
}
調(diào)用:
GenericClass genericClass =new GenericClass("0","張三");
GenericClass mGenericClass =new GenericClass(1,111);
如果要定義超過兩個,三個或三個以上的泛型參數(shù)可以使用T1, T2, ..., Tn,列如:
public class GenericClass<T1,T2,T3>{
public T1 t1;
public T2 t2;
public T3 t3;
public GenericClass(T1 t1, T2 t2, T3 t3) {
this.t1 = t1;
this.t2 = t2;
this.t3 = t3;
}
}
3.2泛型接口
我們上面定義泛型類的時候用的就是泛型接口,泛型接口與泛型類的定義及使用基本相同。泛型接口常被用在各種類的生產(chǎn)器中:
public interface GenericInter<K,V> {
public K getKey();
public V getValue();
}
3.3泛型方法
先說一下泛型類和泛型方法的區(qū)別:泛型類,是在實例化類的時候指明泛型的具體類型;泛型方法,是在調(diào)用方法的時候指明泛型的具體類型 。泛型方法相對比較復雜,我們來看一下:
3.3.1

大家覺得getT()是泛型方法不?答案是:No,
getT()方法雖然使用了泛型,但它的泛型是在泛型類中已經(jīng)聲明了的泛型,所以它才可以使用這個T泛型,getT()不是泛型方法,它算是一個普通成員方法。

大家覺得showGeneric(genericClass<?> obj)是泛型方法不?答案是:No,
showGeneric(genericClass<?> obj)也是一個普通的方法,只不過使用了泛型通配符?,這也印證了泛型通配符?是一種類型實參

真正的泛型方法長這樣:
class genericClass<T> {
public T t;
public genericClass(T t) {
this.t = t;
}
public T getT(){
return t;
}
//正確的泛型方法
public <T> T getGenericClassT(genericClass<T> obj){
return obj.getT();
}
}
要點:真正的泛型方法,在public與返回值之間的<T>必不可少,這表明這是一個泛型方法,并且聲明了一個泛型T。但T可以出現(xiàn)在這個泛型方法的任意位置, 泛型的數(shù)量也可以為任意多個
3.3.2 泛型方法和可變參數(shù)

這個沒啥好說的。
3.3.3 泛型數(shù)組
關(guān)于如何正確創(chuàng)建泛型數(shù)組:
//錯誤創(chuàng)建泛型數(shù)組的方式
List<String> [] mList =new ArrayList<String>[10];
//正確創(chuàng)建泛型數(shù)組方式一,通過通配符?
List<?> [] mListTwo =new ArrayList<?>[10];
//正確創(chuàng)建泛型數(shù)組方式二
List<String>[] mListThree = new ArrayList[10];
總結(jié):在java中是不能創(chuàng)建一個確切的泛型類型的數(shù)組
4.各種泛型的區(qū)別
4.1 List<T>,List<Object>,List<?>的區(qū)別?
ArrayList<T> al=new ArrayList<T>(); 指定集合元素只能是T類型
ArrayList<?> al=new ArrayList<?>(); 集合元素可以是任意類型,沒有意義,一般只是為了說明用法.
- Object和T不同點在于,Object是一個實打?qū)嵉念?并沒有泛指誰,而T可以泛指Object,比方public void printList(List<T> list){}方法中可以傳入List<Object> list類型參數(shù),也可以傳入List<String> list類型參數(shù),但是public void printList(List<Object> list){}就只可以傳入List<Object> list類型參數(shù),因為Object類型并沒有泛指誰,是一個確定的類型
- ?和T區(qū)別是?是一個不確定類,?和T都表示不確定的類型 ,但如果是T的話,函數(shù)里面可以對T進行操作,比方 T car = getCar(),而不能用? car = getCar()。
4.2 T,Class,Class<T>,Class<?>區(qū)別?
- T,是一種具體的類,例如String,List,Map......等等,這些都是屬于具體的類。
- Class,是一個類,但Class是存放上面String,List,Map.....。
注:獲取Class的三種方式:
1.調(diào)用Object類的getClass()方法來得到Class對象
image.png
-
使用Class類的中靜態(tài)forName()方法獲得與字符串對應的Class對象
image.png
3.如果T是Java類型則直接T.calss

-
Classy<T> 在實例化的時候,T要替換成具體類,使用Class<T>還有一個好處就是不用強轉(zhuǎn).
我們看一下不加泛型,反射創(chuàng)建一個類對象,需要強轉(zhuǎn):
image.png
使用Class<T>泛型后,不用強轉(zhuǎn)了:
image.png
-
Class<?>它是個通配泛型,?可以代表任何類型,主要用于聲明時的限制情況
例如,你可以聲明:
public Class<?> clazz;
但不能聲明:
public Class<T> clazz;
因為T需要指定類型,所以當不知道定聲明什么類型的Class的時候可以定義一個Class<?>,Class<?>可以用于參數(shù)類型定義,方法返回值定義等。
以上就是今天的全部內(nèi)容!



