聲明一個泛型類並實例化
Box是一個泛型類,這裏的T是參數傳遞給泛型類的泛型,它可以是任何對象。而t則是T的一個實例。個人理解泛型,就是泛化類型,將具體的類型用統一的類指代。add和get是定義的兩個方法。
public class Box<T>{
private T t;
public void add(T t){
this.t = t;
}
public void get(T t){
return t;
}
}
在main方法中,泛型類這樣使用。其中intbox和strbox都是泛型類的對象,可以調用泛型類中已定義的方法。
Box<Integer> intbox = new Box<Integer>();
Box<String> strbox = new Box<String>();
intbox.add(new Integer(1));
System.out.println(intbox.get());
//調用了泛型類中的方法,打印數字1
泛型類可以有多個類型參數,這就使得泛型可以當C++中的結構體來使用。當然,憑我現有的知識,結構體與類並無本質的差異。同時,可以用參數化類型來代替,比如傳的不只是一個類,而是某個框架,如下例。
public static void main(String[] args){
Box<Integer,String> box = new Box<Integer,String>();
box.add(Integer.valueOf(100),"hello world");
Box2<Integer,List<String>> box2 = new Box2<Integer,List<String>>();
List<String> m = new ArrayList<String>();
m.add("Hello");m.add("world");
box2.add(Integer.valueOf(10),m);//此時的m是一個列表
}
class Box<T,S>{
private T t;
private S s;
public void add(T t,S s){
this.t = t;
this.s = s;
}
}
參數命名約定 也就是尖括號裏的字母,這是一般的約定並無強制要求
字符 | 意義 |
---|---|
E | 由Java集合框架使用(list等) |
K | 表示映射中的鍵值(key) |
V | 表示映射中的值(value) |
N | 表示數字 |
T | 第一類通用參數 |
S | 第二類通用參數 |
U | 第三類通用參數 |
V | 第四類通用參數 |
有界類型參數
什麼是泛型有界類型參數?就是限制允許傳遞給類型參數的類型。簡單來說就是給泛型一定的條件,比如只允許接受Char類或者它的子類實例。要聲明它,只需要後跟extend關鍵字和邊界上限即可。如果需要多重邊界,則用&連接。
public static <T extends Number & Comparable<T>> T maximum(T x,T y,T z){
T max = x;
if(y.compareTo(max)>0){
max = y;
}
if(z.compareTo(max)>0){
max = z;
}
return max;
}
public static void main(String[] args){
System.out.println(maximum(10,20,30));
System.out.println(maximum(22.1,33.2,44.3));
}
Java在List、Set、Map中都提供了泛型的支持,語法如下
List<T> list = new ArrayList<T>();
Set<T> set = new HashSet<T>();
Map<T> map = new HashMap<T>();
通配類型符
首先要知道,爲什麼需要通配類型?《Java語言程序設計》中有一個例子。
public static void main(String[] args){
GenericStack<Integer> intstack = new GenericStack<Integer>();
intstack.push(1);intstack.push(2);
System.out.println(max(intstack));
}
public static double max(GenericStack<Number> stack){
double max = stack.pop().doubleValue();
while(!stack.empty()){
double value = stack.pop().doubleValue();
if(value>max)max=value;
}
return max;
}
這段程序會出現編譯錯誤,原因是雖然Integer是Number的子類,但GenericStack<Integer>
不是GenericStack<Number>
的子類。因此需要通配符規避這種錯誤。
?表示非受限通配符
?extend T 表示T或T的一個未知子類
?super T 表示T或T的一個父類
用public static double max(GeericStack<? extends Number> stack)
就可以改正上面的錯誤。
泛型類型擦除
泛型是使用一種稱爲類型消除的方法來實現的。編譯器使用泛型類型信息來編譯代碼,但是隨後會消除它。因此,泛型信息在運行時是不可用的。這種方法可以使泛型代碼向後兼容使用原始類型的遺留代碼。
泛型在編譯的時候一旦確認其是安全的,就會將它轉換爲原始類型。不管實際的具體類型是什麼,泛型類是被它所有實例共享的。
限制
不能使用E object = new E();
,因爲運行時泛型類型E是不可用的。同理不能創建數組。
異常類不能是泛型。
靜態環境下不允許類的參數是泛型類型。
除非由無界通配符進行參數化,否則不允許轉換爲參數化類型。如下段代碼。
private static void add(Box<?> box){
Box<Integer> intbox = (Box<Integer>) box;
}
無法用instanceof驗證。