泛型的定義:
泛型的本質(zhì)就是參數(shù)化類型的應(yīng)用,也就是說(shuō)所有操作的數(shù)據(jù)類型都被指定為一個(gè)參數(shù)绘雁,在用到的時(shí)候才指定具體的類型橡疼。這種參數(shù)類型可以用在類,接口和方法中創(chuàng)建庐舟,分別稱為泛型類衰齐,泛型接口和泛型方法。
泛型的作用
- 類型安全
泛型的主要目的是提到Java程序的安全继阻,在編譯時(shí)期強(qiáng)制類型檢查耻涛,通過(guò)知道使用泛型泛型定義的變量限制,編譯器可以在一個(gè)高得多得程度上驗(yàn)證類型假設(shè)瘟檩。
- 消除強(qiáng)制類型轉(zhuǎn)換
泛型得作用之一就是消除代碼中得強(qiáng)制類型轉(zhuǎn)換抹缕,減少出錯(cuò)得機(jī)會(huì)。
- 潛在得性能收益
泛型為較大得優(yōu)化帶了可能墨辛,編譯器將強(qiáng)制類型轉(zhuǎn)換卓研,插入到字節(jié)碼文件中,所有得工作都在編譯期間完成睹簇。
- 泛型提高代碼得復(fù)用性
可以通過(guò)泛型提高復(fù)用性奏赘,不需要寫大量重復(fù)的代碼。
泛型使用
泛型類
泛型類型用于定義類太惠,稱為泛型類磨淌,常見(jiàn)的泛型類有List,set凿渊,map梁只。泛型類的定義格式:
class 類名稱<泛型標(biāo)識(shí)符:可以是任意字母>{}
例子:
//泛型類
/**
* 在定義泛型類的時(shí)候,一定要指明泛型表示
* 而我類中如果使用到該泛型埃脏,一定要用與類定義的泛型標(biāo)識(shí)搪锣。
*
* @param <T>
*/
class Generic<T>{
//T類型跟類的是一樣的,由外部指定
public Generic(T value) {
print(value);
}
//泛型類的一個(gè)方法彩掐,但不是泛型方法构舟,只不過(guò)使用了T這個(gè)泛型做為形參而已。
public void print(T value) {
System.out.println(value.toString());
}
}
使用:
Generic<String> strGerneric=new Generic<>("字符類型");
Generic<Integer> intGerneric=new Generic<>(111);
結(jié)果:
注意:
泛型參數(shù)只能是類類型堵幽,不能是簡(jiǎn)單類型
不能對(duì)確切的泛型使用instanceof操作狗超。
泛型接口
定義:
//泛型接口
/**
*和泛型類的定義要求類似弹澎,根式類似,可以指定任意字母當(dāng)標(biāo)識(shí)符
* @param <I>
*/
interface GenericInterface<I> {
void print(I value);
}`
在繼承該接口的時(shí)候可以直接指定具體的類型抡谐,不也可以通過(guò)泛型類的形式使用裁奇。
class Test<I> implements GenericInterface<I>{
@Override
public void print(I value) {
}
}
class GenericTest implements GenericInterface<Integer>{
@Override
public void print(Integer value) {
}
}
泛型方法
泛型方法在定義的時(shí)候要注意格式,在定義的時(shí)候在方法類型返回的返回簽名加上<標(biāo)識(shí)符>
class GenericMethod<T> {
/**
* 泛型方法,雖然泛型的標(biāo)識(shí)符與泛型類的相同都是T麦撵,但是兩者卻是不同
* 泛型方法中需要定義泛型標(biāo)識(shí)刽肠,例如<T>
* @param value
* @return
*/
public <T> T method1(T value) {
return value;
}
public <M> void method2(M value) {
}
/**
* 這個(gè)不是泛型方法,只是利用泛型做為形參
* @param value
*/
public void notMethod(T value) {}
//也可以定義一個(gè)泛型方法與可變參數(shù),例如使用的時(shí)候可以 genericMethod.changeParamsMethod(1,2,3);
public <T> void changeParamsMethod(T... valuse) {
for(T t:valuse) {
System.out.println(t);
}
}
/**
* 在靜態(tài)方法中免胃,是使用不了泛型類定義的標(biāo)識(shí)的音五,例如下面是會(huì)報(bào)錯(cuò)
*/
/**
* public static void staticMethod(T value) {}
* 因?yàn)殪o態(tài)方法是不持有類的引用,是訪問(wèn)不了類非靜態(tài)的方法羔沙,變量等躺涝。因此我們必須用泛型方法
*/
public static <T> void staticMethod(T value) {
}
}
泛型通配符
Integer是Number的子類,那么我們下面的那部分的代碼會(huì)不會(huì)有問(wèn)題呢扼雏?
可以看到上面的方法已經(jīng)報(bào)錯(cuò)了坚嗜,所明是不行的,通過(guò)提示信息我們可以看到Generic<Integer>不能被看作為`Generic<Number>的子類诗充。由此可以看出:同一種泛型可以對(duì)應(yīng)多個(gè)版本(因?yàn)閰?shù)類型是不確定的)苍蔬,不同版本的泛型類實(shí)例是不兼容的,那么如何解決呢蝴蜓?首先我們可以通過(guò)泛型方法來(lái)解決上面的問(wèn)題碟绑,還有就是通過(guò)泛型通配符。
public static void main(String[] args) {
Generic<Integer> genericInteger=new Generic<>(1);
Generic<Number> genericNumber=new Generic<>(1);
showKey(genericInteger);
showKey(genericNumber);
showKeyWildcard(genericInteger);
showKeyWildcard(genericNumber);
}
/**
* 泛型方法
* @param nGeneric
*/
private static <T> void showKey(Generic<T> nGeneric) {
System.out.println(nGeneric.hashCode());
}
/**
* 泛型通配符
* @param value
*/
private static void showKeyWildcard(Generic<?> value) {
System.out.println(value.hashCode());
}
泛型通配符的類型
- 無(wú)邊界通配符:<?>
使用外邊界的通配符可以讓泛型接受任意類型的數(shù)據(jù)
- 上邊界通配符:<? extends 具體類型>
使用固定上邊屆的通配符的泛型可以接收的是指定類型及其子類類型的數(shù)據(jù)茎匠。
- 下邊界通配符:<? super 具體類型>
使用固定下邊界的通配符的泛型可以接收指定類型及其所有超類類型的數(shù)據(jù)格仲。
泛型的擦除
Java的泛型是偽泛型,泛型基本導(dǎo)航都是在編譯器這個(gè)層次來(lái)實(shí)現(xiàn)的诵冒,生成的Java類型字節(jié)碼中是不包含泛型的類型凯肋。使用泛型的時(shí)候加上的泛型參數(shù),會(huì)在編譯器在編譯的時(shí)候去掉造烁,這個(gè)過(guò)程就是泛型擦除否过。具體參考泛型的擦除