JAVA泛型知識點
1.概述
泛型:即“參數化類型”。將類型由原來的具體類型參數化,類似於方法中的變量參數,此時類型同樣定義為參數形式,只有在調用/運行時才傳入具體的類型。
泛型的本質:為了參數化類型,即在不創建新的類型的情況下,通過反省制定的不同類型來控制形參具體顯限制的類型,也就是說在使用泛型的過程中,操作的數據類型被指定為某一參數時,改類型可以用在泛型類、泛型接口、泛型方法中。
2.特性
泛型只在編譯階段有效--->由於JVM的泛型類型擦除。
List<String> l1 = new ArrayList<String>(); List<Integer> l2 = new ArrayList<Integer>(); /*輸出結果為true*/ System.out.println(l1.getClass() == l2.getClass());
在編譯過程中,驗證泛型的類型正確性之後,將相關信息擦除。即泛型類型在編譯階段看似多個不同的類型,實際在編譯之後的階段,都是相同的基本類型。
3.泛型的使用
- 泛型類
- 泛型接口
- 泛型方法
3.1 泛型類
通過泛型可以完成對一組類的操作對外開放相同的接口,典型有各種容器類:List、Set、Map等。
泛型類的基本寫法:
class 類名 <泛型標識>{ /*該處T(泛型標識)由外部制定*/ private 泛型標識 成員變量名; /** *@param 自定義 *@return 返回泛型標識類型的類型 */ public 泛型標識 成員變量名(@param T t){} }
註
泛型標識:可以寫為任意標識,常見的如T、E、K、V。
實例化泛型類時,必須制定T的具體類型(包括自定義類),不能使簡單類型(如int、double)。
3.2 泛型接口
泛型接口常被用在各種類的生產器中。
泛型接口的基本寫法:
public interface 接口名<泛型標識/*這裏用T*/>{ public T 方法名(); } /** *未傳入泛型實參時,與泛型類的定義相同,在聲明類的時候,需將泛型的聲明也一起加到類中 *如不聲明,編譯器報錯:"Unknown class" */ class ImplGenerator<T> implements Generator<T>{ @override public T next(){ return null; } }
3.3 泛型通配符
如:
public void showKetValue(Geberic<?> obj){
Log.d("泛型測試","key value is " + obj.getKey());
}
註:
類型通配符一般是使用?代替具體的類型實參。和Integer、String一樣都是一種實際的類型。
使用場景:可以解決當具體類型不確定的時候,這個通配符就是?;當操作類型時,不需要使用類型的具體功能時,只是用Object類中的功能,那麽可以用?通配符來表示未知類型。
3.4 泛型方法
大多數泛型類中的成員方法也是用了泛型,甚至有的泛型類中包含著泛型方法,學習時要註意區分。
泛型類:在實例化類的時候指明泛型的具體類型;泛型方法:在調用方法的時候指明泛型的具體類型。
泛型方法可出現在任意地方和任意場景中使用。
泛型方法的基本寫法:
/**
*@param t 傳入泛型實參
*@return T 返回類型為T
*說明:
*1)只有聲明了public和返回類型中間的<T>才是泛型方法
*2)<T>表示四該方法將使用的泛型類型為T,諸如T、E、K等,該T可出現在泛型方法任意位置
*3)Class<T>中的T表示為該類的泛型類型
*4)泛型的數量也可以為任意多個
*如:
*public <T,K> K showKeyName(Generic<T> container){...}
*/
public <T> genericMethod(Class<T> t) throws InstantiationException,
IllegalAccessExceotion{
T instance = t.newInstance();
return instance;
}
3.4.1 泛型方法與可變函數
如:
public <T> void printMsg(T...args){
for(T t:args){
Log.d("Test"," t is " + t);
}
}
3.4.2 靜態方法與泛型
類中的靜態方法使用泛型:靜態方法無法訪問類上定義的泛型,方法操作的引用數據類型不確定的時候,必須要將泛型定義在該靜態方法上。
如:
public class StaticGenerator<T> {
....
/**
*如果在類中定義使用泛型的靜態方法,需要添加額外的泛型聲明(將這個方法定義成泛型方法)
*即使靜態方法要使用泛型類中已經聲明過的泛型也不可以。
*如:public static void show(T t){..},此時編譯器會提示錯誤信息:
"StaticGenerator cannot be refrenced from static context"
*/
public static <T> void show(T t){}
}
3.4.3 泛型方法總結
泛型方法可獨立於類產生變化,基本原則如下:
無論何時,如果能做到,就盡量使用泛型方法,也就是說,如果使用泛型方法將整個類泛型化,那麽就應該使用泛型方法。另外,對於一個static的方法,無法訪問泛型類型的參數。所以如果要事static方法使用泛型能力,就必須使其成為泛型方法。
4. 泛型的上下邊界
- 添加上邊界,即傳入的類型實參必須是指定參數或其子類型
public void showKeyValue(Generic<? extends Number> obj){}
- 添加下邊界,即傳入的類型實參必須是制定參數或其父類
public void showKeyValue(Generic<? super Integer> obj){}
- 無邊界,即通配符?,參看"3.3泛型通配符"
例子:
//在泛型方法中添加上下邊界限制的時候,必須在權限聲明與返回值之間的<T>上添加上下邊界,即在泛型聲明的時候添加
//public <T> T showKeyName(Generic<T extends Number> container),編譯器會報錯:"Unexpected bound"
public <T extends Number> T showKeyName(Generic<T> container){
System.out.println("container key :" + container.getKey());
T test = container.getKey();
return test;
}
註:泛型的上下邊界添加,必須與泛型的聲明在一起
JAVA泛型知識點