1、為什么使用泛型
泛型是指參數(shù)化類型的能力。可以定義帶有泛型類型的類或類,隨后編譯器會使用具體的類型來代替它。
使用泛型會有如下好處:
1、類型安全。泛型的主要目的是為了提高Java程序的類型安全。
2、消除強制類型轉(zhuǎn)換。消除代碼中的強制類型轉(zhuǎn)換,提高代碼的可讀性,減少出錯的機會。
3、潛在的性能收益。為JVM優(yōu)化提供可能性
2、泛型的原理
Java有Java編譯器和Java虛擬機,編譯器將Java源代碼轉(zhuǎn)換為.class文件,虛擬機加載并運行.class文件。對于泛型類,Java編譯器會將泛型代碼轉(zhuǎn)換為普通的非泛型代碼,將類型參數(shù)T擦除,替換為Object,插入必有的強制類型轉(zhuǎn)換。這樣做是為了實現(xiàn)兼容性的。知道這一點對于理解Java泛型的許多限制很有用。
3、泛型的使用
泛型類的定義
class 類名稱 <泛型標識:可以隨便寫任意標識號,標識指定的泛型的類型{
private 泛型標識 /*(成員變量類型)*/ var;
}
}
泛型接口的定義
//定義一個泛型接口
public interface Generator<T> {
public T next();
}
泛型方法的定義
public <T> T genericMethod(Class<T> tClass)throws InstantiationException ,
IllegalAccessException{
T instance = tClass.newInstance();
return instance;
}
總結(jié):泛型類和泛型接口的類型參數(shù)都是跟在接口名或類名之后,而泛型方法的類型參數(shù)在方法返回值之前。
4、泛型的局限
1、不能使用基本類型實例化類型參數(shù)
因為泛型在執(zhí)行類型擦除后,變成了Object類型的域,而Object是不能存儲如int這樣的基本類型
2、不能創(chuàng)建參數(shù)類型的數(shù)組
3、不能實例化類型變量T
因為在編譯的過程中就進行了類型擦除,在需要的實例化的時候找到合適的構(gòu)造函數(shù)
4、泛型類的靜態(tài)上下文中類型參數(shù)失效
參數(shù)類型是在實例化泛型類型的時候才會傳入,而靜態(tài)的上下文會脫離具體類而存在,所以類型參數(shù)會失效。
5、泛型中T ? extends super的理解
在這個問題上,可以分為兩類來說明,首先是 T 和?表示類型,而extends和super表示上限。
在泛型定義的時候,使用T,T extends,或者T super等,如果需要多個不同類型的泛型,則可以加上E S等,其實使用 T E S沒有太大的區(qū)別僅僅是字母的名字不相同而已。
//在泛型的使用中,對于賦值的語句
//應該從兩個方面來理解,等號左邊
//定義了變量的類型,如list是一個能夠存放Number子類的list。
//等號右邊就是要賦值的內(nèi)容,只要符合就可以賦值成功
List<? extends Number> list = null;
List<Integer> list1 = new ArrayList<>();
//對于使用通配符定義的泛型類型變量,
//只能訪問其中的值,不能通過該變量
//來修改集合中的內(nèi)容,但可以通過原
//來的集合來修改集合的內(nèi)容。
list1.add(9);
list = list1;
System.out.println(list.get(0));
list1.add(10);
System.out.println(list.get(1));
在定義類或者方法時候
class TestAnimals <T extends Annimals>{
T anni;
public TestAnimals(T anni) {
this.anni = anni;
}
public void test() {
anni.say();
}
}
//這種方法是有問題的,因為在進行類型擦除的時候無法知道上限
class TestAnimals <T super Dog>{
T anni;
public TestAnimals(T anni) {
this.anni = anni;
}
public void test() {
anni.say();
}
}
但是使用泛型的時候,可以使用?來定義接受參數(shù)的上限和下限。
盡管使用通配符?,但是在具體的一次使用中還是只能有一個確定的類型。
List<?> listOrg1 = null;
List<Integer> list1 = new ArrayList<>();
List<Object> list2 = new ArrayList<>();
listOrg1 = list1;
listOrg1 = list2;
//可以對已經(jīng)賦過值得泛型變量重新賦值,在
//具體一次使用泛型變量的過程中還是只有一個
//具體的類型。
List<? super Number> listOrg1 = null;
List<Integer> list1 = new ArrayList<>();
List<Object> list2 = new ArrayList<>();
listOrg1 = list1; //編譯錯誤
listOrg1 = list2;
List<? extends Number> listOrg2 = null;
List<Integer> list3 = new ArrayList<>();
List<Object> list4 = new ArrayList<>();
listOrg2 = list3;
listOrg2 = list4;//編譯錯誤