什么是泛型
Java泛型(generics) 是JDK5中引入的一個(gè)新特性蜂大,泛型提供了編譯時(shí)類型安全檢測(cè)機(jī)制,該機(jī)制允許程序員在編譯時(shí)檢測(cè)到非法的類型泛型的本質(zhì)是參數(shù)類型,也就是說(shuō)所操作的數(shù)據(jù)類被指定為一個(gè)參數(shù)泛型不存在于JVM虛擬機(jī)
泛型的好處
泛型可以增強(qiáng)編譯時(shí)錯(cuò)誤檢測(cè)照瘾,減少因類型問(wèn)題引發(fā)的運(yùn)行時(shí)異常泛型具有更強(qiáng)的類型檢查
泛型可以避免類型轉(zhuǎn)換
分型可以泛型算法,增加代碼復(fù)用性
泛型的類型
-
泛型類
public class Test1<T> {}
-
泛型接口
public interface Test1<T> {}
-
泛型方法
public <T> void a(T t) {} public void test(List<String> list){}//這不是泛型方法
PECS法則
? List<?> 非限定通配符 是一個(gè)泛型類型 飘蚯? 位置 等價(jià)于 List<? extends Object>
? List<? extends T> List<? super T> 統(tǒng)稱為限定通配符
? 非限定通配符不能寫(xiě)也不能讀 但也有好處,編譯還是會(huì)進(jìn)行類型安全檢查
- extends :上界只取不存 消費(fèi)者
可以發(fā)現(xiàn) 通過(guò)調(diào)用add 方法無(wú)法添加福也,但是可以通過(guò)反射的方式添加數(shù)據(jù)
但是取出來(lái)的時(shí)候可以發(fā)現(xiàn)如果不強(qiáng)轉(zhuǎn)的話會(huì)報(bào)錯(cuò)局骤,但是運(yùn)行期還是原本的類型
-
super:下界只存不取
1587695807772.png
可以發(fā)現(xiàn) 用過(guò)get方法取的時(shí)候是Object 而不是Apple 但是實(shí)際類型是Apple,Kotlin稱之為逆變暴凑,java沒(méi)有這種說(shuō)法
協(xié)變
A的父類是B
A[] 就是 B[]的協(xié)變
例子:
public static <T> void copy(List<? super T> dest, List<? extends T> src){}//左邊是只存不取峦甩,右邊只取不存
泛型擦除
由于泛型是JDK5引入的 為了做到向下兼容 所有JVM里面是不存在泛型的,代碼里寫(xiě)的泛型现喳,在編譯期的時(shí)候會(huì)轉(zhuǎn)換成具體的類型凯傲,如果沒(méi)有就會(huì)被擦除,變成Object
可以看出 setT方法在.class文件的時(shí)候還是T 但是到了字節(jié)碼文件就變成了Object
泛型的副作用
- 泛型不行是 基本數(shù)據(jù)類型 必須是包裝類
- 不能使用 instanceof 運(yùn)算符(擦除類型丟失)
- 類的泛型不能再靜態(tài)方法中使用 (加載順序不一樣嗦篱,靜態(tài)先加載的冰单,類是實(shí)例加載的,所以靜態(tài)方法無(wú)法獲取類的泛型)
其他
這種形式的寫(xiě)法 <T> 沒(méi)有任何用處 編譯期會(huì)給T打一個(gè)標(biāo)識(shí) 和LinearLayout沒(méi)什么關(guān)系只認(rèn)ViewGroup 所以要強(qiáng)轉(zhuǎn)默色, 甚至我可以給這個(gè)泛型RelateLayout類型這樣明顯就不是LinearLayout了 所以說(shuō)球凰,jvm并不知道具體是什么類
最后
Plate 沒(méi)有寫(xiě)泛型,編譯期不會(huì)進(jìn)行類型檢查
Plate<Object> 會(huì)編譯成Object類型 算是沒(méi)有泛型
Plate<?> 編譯會(huì)進(jìn)行類型檢查
Plate<T> 編譯泛型會(huì)被擦除變成Object
Plate<? extends T> 上界 可取不可存 但是可以通過(guò)反射進(jìn)行存儲(chǔ)
Plate<? super T> 下界 可存不可取 取出的類型是Object 需要進(jìn)行強(qiáng)轉(zhuǎn)