java学习笔记 ——泛型

  

  泛型:

-  虚拟机中没有泛型,只有普通的类和方法

-  擦除时,所有类型参数都用他们的限定类型替换(默认为Object)

-  一般通过 桥方法 保持多态(在桥方法中,调用泛型类对应的重写方法)

注意事项:

-  不能用基本类型作为泛型:

    擦除后Object不能存储基本类型数据, 但基本类型并不多,可以使用独立的类和方法特别处理

-  运行时类型查询只适用原始类型 :

    同一个泛型类的两个对象即使泛型不同,getClass()返回的原始类型也相同

-  不能创建参数化类型的数组 :

    擦除后,数组相当是 Object[],数组会记得元素类型,若尝试插入其他类型的元素,会弹出ArrayStoreException异常

    但若尝试插入相同类下不同泛型的对象,则可以通过编译

    Ps: 可以声明一个泛型数组,只是不能用new 方法初始化,可以声明通配类型的数组然后强制转换

       eg: Pair<String>[] arr =  (Pair<String>[]) new Pair<?>[10];

    但仍然是不安全的,仍可以插入不同泛型的对象,如果对数组中不同泛型的对象调用方法,可能出现ClassCastException

-   如果需要收集参数化类型对象, 只有一种安全而有效的方法:使用 ArrayList:   ArrayList<Pair<String>>

-   向参数个数可变的方法传递泛型类型实例,虚拟机实际上创建了一个泛型类型的数组,这与之前的规则冲突,会出现警告

    如果我们确定传入参数类型正确,可以用注解的方式抑制警告

      @SuppressWarnings("unchecked")

      @SafeVarargs

    但这种情况仍有隐患,擦除后的Object数组,仍不能识别出 对象是否为相同泛型,插入时仍不会报错,

    但在实际使用时会出现异常。

-  不能实例化泛型的类型变量

    以<T>为例, new T(), T.class 等都是不合法操作。所以下面的构造器也是非法的:

      public Pair() { first = new T(); second = new T(); } // 会有Error  

   因为T.class 是不合法的,如果想用反射Class.newInstance方法构造也是不允许的。

  

   在JAVA 8 之后,可以让调用者提供一个构造器表达式,如:

       // Supplier<T> 是一个函数式接口,表示一个无参数并且返回类型为 T 的函数

        public static <T> Pair<T> makePair(Supplier<T> constr){
          
            return new Pair<>(constr.get(),constr.get());

        }
   接下来就可以使用如下语句:
      Pair<String> p = Pair.makePair(String.class);

   ps: Class类本身是泛型, String.class是 Class<String> 的实例(也是唯一的实例)

-  不能构造泛型数组

    在方法中,如果出现  T[] ts = new T[2]; 会报告Error  ,因为在擦除后,都会转换为泛型的约束类型数组

-  不能在静态域或静态方法引用泛型

    同样是擦除的原因,擦除后没有具体类型,就不能工作。

-  要注意擦除后的冲突

    如果有和Object类相同名字的方法,在擦除后会出现两个一样的方法,而出现错误。 

    ps: 如果父类实现了一个带泛型<A>的接口,子类不能再实现 带泛型<B>的该接口。

泛型与继承的关系

-  假设有 Father , Son 两个类,并且Son类为Father类的子类。

  当二者作为泛型时,相应的对象之间没有联系, 如Pair<Son> 与 Pair<Father> 对象不能相互赋值

-   要解决上述情况,希望可以建立联系,可以用通配符 Pair<? extends Father> 

   但若是 Pair中有参数为泛型类型的 方法,在通配符的对象中,就会因为无法匹配通配符而出错。

   假设存在一个方法  void setSon(Son); 如果使用了通配符,就会变成 void setSon(? extends Father);就会出现 compile-time error 

   而如果是一个无参方法返回通配类型,则不会出现问题  :  ? extends Father getSon();

-  通配符的另一个用法

    Pair< ? super Son> 表示可以匹配Son以及Son的所有父类

泛型Class类

  java.lang.Class<T>  有以下常用方法 (是Class对象可以调用的方法)

    

   T newInstance()  返回无参构造器构造的一个新实例

  T cast(Object obj) 如果obj为NULL或者有可能转换为T,则返回obj,否则抛出 BadCastException

  T[] getEnumConstants() 如果T是枚举类型,则返回所有值组成的数组,否则返回NULL

  Class<? super T> getSupercalss() 返回这个类的父类,如果T不是类或为Object,则返回NULL

  Constructor<T> getConsructor(Class... parameterTypes)    获得共有的构造器

  Constructor<T> getDeclaredConsructor(Class... parameterTypes)  获得带有给定参数类型的构造器

  T newInstance(Object...parameters)  返回用指定参数构造的新实例

  

  

猜你喜欢

转载自www.cnblogs.com/xfdmyghdx/p/10506690.html