java進(jìn)階-泛型

一、何為泛型?

? ? jdk1.5之后引入泛型概念,可定義泛型類、接口、方法,且編譯期會將泛型擦除,向下兼容;

二、泛型的優(yōu)點(diǎn)?

? ? 2.1? 編輯代碼時保證類型安全,且省去強(qiáng)制類型轉(zhuǎn)化

? ? ? ? 1.5之前代碼:

? ? ? ? ? List list = new ArrayList();

? ? ? ? ? list.add(1);

? ? ? ? ? list.add("test");

? ? ? ? ? String element = (String)list.get(0);//編譯器會報(bào)錯

? ? ? ? ? element = (String) list.get(1); //強(qiáng)制類型轉(zhuǎn)化

? ? ? ? 1.5引入泛型之后:

? ? ? ? ? ?List<String> list = new ArrayList<>();

? ? ? ? ? ?list.add(1);//編譯器報(bào)錯

? ? ? ? ? ?list.add("test");

? ? ? ? ? ?String element = list.get(0);//不用強(qiáng)制類型轉(zhuǎn)化

? ? 2.2 代碼復(fù)用

? ? ? ? 比如實(shí)現(xiàn)數(shù)字排序的算法sort();

? ? ? ? 定義 public static <T> void sort(T[] a, Comparator<? super T> c),所有實(shí)現(xiàn)了Comparator的接口的類型都可以進(jìn)? ? ? ? ? 行排序算法,如果沒有泛型,則需要針對int,double,float等各自實(shí)現(xiàn)一套sort算法

三、泛型的使用

? ? 3.1 泛型類、接口一樣

? ? ? ? public class A<T> {};

? ? ? ? punlic classA<T extends B> {}

? ? 3.2 泛型方法(返回類型之前必須有<>),可以定在普通類也可定義在泛型類,但是在泛型類中定義時各自維護(hù)各自的泛型T

? ? ? ? public <T> void set(T t);

? ? ? ? public <T extends B> void set(T t);

? ? ? ? public <T> T get();

四、通配符 ? 靈活轉(zhuǎn)型(如網(wǎng)絡(luò)架構(gòu)Rxjava)

? ? 4.1 非限定通配符 ?;? ? ?A<?> a? 等價于 A<? extends Object> 既不能讀也不能寫,但作為方法入?yún)⒖蛇M(jìn)行類型安全檢驗(yàn),另外作為引用時只進(jìn)行Object相關(guān)操作也可,最典型的是Class<?> clz;

? ? 4.2 上界通配符<? extends T>;? 只能讀不能存(原因下面的繼承關(guān)系中講)

? ? 4.3 下界通配符<? super T>;? 只能存且存T或者T的子類,不能讀T,但是能讀返回Object

五、泛型與繼承、多態(tài)

? ? 5.1 繼承:

????????class A<T>{};? class B<T> extends A<T> 或者 class B extends A<String>

? ? ? ? class C extends D{}, class D extends E{};? List<C> 與 List<D>沒有繼承關(guān)系; 但是List<C>是ArrayList<C>的父類,只要泛型不變,則類的繼承關(guān)系不變;

? ? ? ? List<?> -> List<? extends D> -> (List<D> 和List<C>)? 父類關(guān)系成立(左側(cè)是父類) ;

? ? ? ? List<? extends D> list = new ArrayList<D>(); 或者? List<? extends D> list = new ArrayList<C>();正因?yàn)檫@層繼承關(guān)系,所以list引用可執(zhí)行D的容器,也可指向C的容器,對于JVM來說,不清楚你最后可能指向的是哪個容器,所以禁止?上界通配符定義的變量能存放數(shù)據(jù),否則會涉及類型安全問題。


? ? ? ? List<?> -> List<? super D> -> (List<D>和List<E>)?

六、JVM如何實(shí)現(xiàn)泛型?

? ? 6.1 編譯前進(jìn)行類型檢查,編譯后進(jìn)行類型擦除,擦除的泛型信息保存在常量池中,通過反射可獲??;

? ? ? ? List<C> listC = new ArrayList<>();? List<D> listD = new ArrayList<>();? listC.getClass 與 listD.getClass是一樣的,都是List;這就是類型擦除;

? ? 6.2 類型擦除原則如下:

? ? ? ? ? ?沒有限定則Object

? ? ? ? ? ?有則用限定類型

? ? ? ? ? ?橋方法維護(hù)多態(tài)性

? ? ? ? ? ?擦除了但依舊可以通過反射獲得泛型類,類常量池有保存泛型類信息

? ? 6.3 泛型后遺癥如下:

? ??????1、不能實(shí)例化類型變量 new T(),可以通過反射獲得實(shí)例;

? ? ? ? 2、static T t? static void set(T t)靜態(tài)屬性或者方法里不能引用類型變量,對象創(chuàng)建的時候才知道類型,static屬于類,先執(zhí)行,此時還不知道具體是什么類型;靜態(tài)泛型方法可以static <T> void set(T t)

? ? ? ?3、基本類型不支持作為實(shí)參,List<double> list 不行,List<Double> 可以

? ? ? ?4、instanceof不支持(泛型擦除導(dǎo)致,沒有了類型信息)? 如果是A<? extents B>? 這個能用instanceof嗎?

? ? ? ?5、泛型數(shù)組不支持

? ? ? ? A extents B? A[] 的分類是 B[]? 數(shù)組的協(xié)變

? ? ? ? 類型擦除后不能支持協(xié)變了

? ? ? ?6、泛型類不能extends Exception/Throwable,也不能catch泛型類對象,但是可以catch exception然后throws出來即可

七、總結(jié):

? ? 泛型設(shè)計(jì)初衷就是為了靈活的實(shí)現(xiàn)類型轉(zhuǎn)型,這樣設(shè)計(jì)和開發(fā)通用功能模塊時可對用戶透明,解耦且通用,強(qiáng)行記住上下界規(guī)則PECS(Product extends Consumer super),上不存下不取或者上只讀下只寫。

??

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容