什么是泛型
Java泛型(generics) 是JDK5中引入的一個新特性,泛型提供了編譯時類型安全檢測機制,該機制允許程序員在編譯時檢測到非法的類型泛型的本質是參數類型,也就是說所操作的數據類被指定為一個參數泛型不存在于JVM虛擬機
泛型的好處
泛型可以增強編譯時錯誤檢測,減少因類型問題引發的運行時異常泛型具有更強的類型檢查
泛型可以避免類型轉換
分型可以泛型算法,增加代碼復用性
泛型的類型
-
泛型類
public class Test1<T> {}
-
泛型接口
public interface Test1<T> {}
-
泛型方法
public <T> void a(T t) {} public void test(List<String> list){}//這不是泛型方法
PECS法則
? List<?> 非限定通配符 是一個泛型類型 ? 位置 等價于 List<? extends Object>
? List<? extends T> List<? super T> 統稱為限定通配符
? 非限定通配符不能寫也不能讀 但也有好處,編譯還是會進行類型安全檢查
- extends :上界只取不存 消費者
可以發現 通過調用add 方法無法添加,但是可以通過反射的方式添加數據
但是取出來的時候可以發現如果不強轉的話會報錯,但是運行期還是原本的類型
-
super:下界只存不取
1587695807772.png
可以發現 用過get方法取的時候是Object 而不是Apple 但是實際類型是Apple,Kotlin稱之為逆變,java沒有這種說法
協變
A的父類是B
A[] 就是 B[]的協變
例子:
public static <T> void copy(List<? super T> dest, List<? extends T> src){}//左邊是只存不取,右邊只取不存
泛型擦除
由于泛型是JDK5引入的 為了做到向下兼容 所有JVM里面是不存在泛型的,代碼里寫的泛型,在編譯期的時候會轉換成具體的類型,如果沒有就會被擦除,變成Object
可以看出 setT方法在.class文件的時候還是T 但是到了字節碼文件就變成了Object
泛型的副作用
- 泛型不行是 基本數據類型 必須是包裝類
- 不能使用 instanceof 運算符(擦除類型丟失)
- 類的泛型不能再靜態方法中使用 (加載順序不一樣,靜態先加載的,類是實例加載的,所以靜態方法無法獲取類的泛型)
其他
這種形式的寫法 <T> 沒有任何用處 編譯期會給T打一個標識 和LinearLayout沒什么關系只認ViewGroup 所以要強轉, 甚至我可以給這個泛型RelateLayout類型這樣明顯就不是LinearLayout了 所以說,jvm并不知道具體是什么類
最后
Plate 沒有寫泛型,編譯期不會進行類型檢查
Plate<Object> 會編譯成Object類型 算是沒有泛型
Plate<?> 編譯會進行類型檢查
Plate<T> 編譯泛型會被擦除變成Object
Plate<? extends T> 上界 可取不可存 但是可以通過反射進行存儲
Plate<? super T> 下界 可存不可取 取出的類型是Object 需要進行強轉