java进阶-泛型

一、何为泛型?

    jdk1.5之后引入泛型概念,可定义泛型类、接口、方法,且编译期会将泛型擦除,向下兼容;

二、泛型的优点?

    2.1  编辑代码时保证类型安全,且省去强制类型转化

        1.5之前代码:

          List list = new ArrayList();

          list.add(1);

          list.add("test");

          String element = (String)list.get(0);//编译器会报错

          element = (String) list.get(1); //强制类型转化

        1.5引入泛型之后:

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

           list.add(1);//编译器报错

           list.add("test");

           String element = list.get(0);//不用强制类型转化

    2.2 代码复用

        比如实现数字排序的算法sort();

        定义 public static <T> void sort(T[] a, Comparator<? super T> c),所有实现了Comparator的接口的类型都可以进          行排序算法,如果没有泛型,则需要针对int,double,float等各自实现一套sort算法

三、泛型的使用

    3.1 泛型类、接口一样

        public class A<T> {};

        punlic classA<T extends B> {}

    3.2 泛型方法(返回类型之前必须有<>),可以定在普通类也可定义在泛型类,但是在泛型类中定义时各自维护各自的泛型T

        public <T> void set(T t);

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

        public <T> T get();

四、通配符 ? 灵活转型(如网络架构Rxjava)

    4.1 非限定通配符 ?;     A<?> a  等价于 A<? extends Object> 既不能读也不能写,但作为方法入参可进行类型安全检验,另外作为引用时只进行Object相关操作也可,最典型的是Class<?> clz;

    4.2 上界通配符<? extends T>;  只能读不能存(原因下面的继承关系中讲)

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

五、泛型与继承、多态

    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>没有继承关系; 但是List<C>是ArrayList<C>的父类,只要泛型不变,则类的继承关系不变;

        List<?> -> List<? extends D> -> (List<D> 和List<C>)  父类关系成立(左侧是父类) ;

        List<? extends D> list = new ArrayList<D>(); 或者  List<? extends D> list = new ArrayList<C>();正因为这层继承关系,所以list引用可执行D的容器,也可指向C的容器,对于JVM来说,不清楚你最后可能指向的是哪个容器,所以禁止 上界通配符定义的变量能存放数据,否则会涉及类型安全问题。


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

六、JVM如何实现泛型?

    6.1 编译前进行类型检查,编译后进行类型擦除,擦除的泛型信息保存在常量池中,通过反射可获取;

        List<C> listC = new ArrayList<>();  List<D> listD = new ArrayList<>();  listC.getClass 与 listD.getClass是一样的,都是List;这就是类型擦除;

    6.2 类型擦除原则如下:

           没有限定则Object

           有则用限定类型

           桥方法维护多态性

           擦除了但依旧可以通过反射获得泛型类,类常量池有保存泛型类信息

    6.3 泛型后遗症如下:

        1、不能实例化类型变量 new T(),可以通过反射获得实例;

        2、static T t  static void set(T t)静态属性或者方法里不能引用类型变量,对象创建的时候才知道类型,static属于类,先执行,此时还不知道具体是什么类型;静态泛型方法可以static <T> void set(T t)

       3、基本类型不支持作为实参,List<double> list 不行,List<Double> 可以

       4、instanceof不支持(泛型擦除导致,没有了类型信息)  如果是A<? extents B>  这个能用instanceof吗?

       5、泛型数组不支持

        A extents B  A[] 的分类是 B[]  数组的协变

        类型擦除后不能支持协变了

       6、泛型类不能extends Exception/Throwable,也不能catch泛型类对象,但是可以catch exception然后throws出来即可

七、总结:

    泛型设计初衷就是为了灵活的实现类型转型,这样设计和开发通用功能模块时可对用户透明,解耦且通用,强行记住上下界规则PECS(Product extends Consumer super),上不存下不取或者上只读下只写。

  

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容