黑马程序员:Java培训、Android培训、iOS培训、.Net培训

JAVA泛型-通配符

一、泛型与继承

      有如下的继承关系和以它们为类型参数的泛型:

     

     public class Holder<T>{

         T t;

         public Holder(){}

         public Holder(T at){ t = at;}

         public void set(T at){ t = at;}

         public T get(){return t; }

     }

    //有如下代码:

    Holder<Apple> apple = new Holder<Apple>(new Apple());

    Holder<Fruit> fruit = apple;  //ERROR,因为Holder<Fruit>与Holder<Apple>不同一类型

    Holder raw = apple;        //原始类型

    raw.set(new Apple());       //only a compile-time warming

可见,尽管泛型的类型参数存在着继承关系,但它们相应的泛型一点关系也没有。

现在有一个问题:能不能将一个涉及Apple的泛型赋给一个涉及Fruit的泛型?这显然不行。因为Apple的的Holder不是Fruit的Holder,不存在向上转型。但,我们如何在这两个类型之间建立某种类型的向上转型关系,这就是通配符的作用。

二、通配符:泛型类型被限定为单一边界

    1、<? exteds T >

        1)上限通配,也称为:子类型通配符

        2)可读作:具有T类型的某种子类作为类型参数的类。

        3)但,这不意味:这个类可持有任何T类型的子类。它只能持有T类型的某种子类或T类型。

        4)有了子类型通配,使得我们可以安全地获得一个泛型类型对象中的对象(可调用返回类型为T的函索):

Holder rawHolder = new Holder(new Apple());

 Holder<Apple> appleHolder = new Holder<Apple>(new Apple());

               Holder<Fruit> fruitHolder = new Holder<Fruit>(new Apple());

               fruitHolder = appleHolder;  //ERROR

 

               Holder<? extends Fruit> boundedHolder = appleHolder;

               boundedHolder = fruitHolder;

               Fruit fruit = boundedHolder.get();

               Apple apple = (Apple) boundedHolder.get();

 

        5)Holder<? exteds T >可合法指向Holder< T’s subclass >或Holder<T >。这种指向(类型的向上转型)是有代价的:禁止调用任何含有T类型参数的函数(这个T类型转换为“? exteds T”,编译器无法理解)。例如:

               Holder<? extends Fruit> boundedHolder = appleHolder;

               boundedHolder.set(new Apple()); //ERROR

               boundedHolder.set(new Fruit());  //ERROR

2、<? super T>

   1)上限通配 ,也称为:超类型通配符

   2)读作:具有T类型的某种父类作为类型参数的类。

       3)不能对泛型参数给出一个超类型边界,即不能声明为<T super MyClass>

       4)有了超类型通配,使得我们可以安全地传递一个类型对象到泛型类型对象中(编译器虽然不知道set()方法内的参数的确切类型,但可用任意T对象<或子类>调用,而不能用T’s supclass)(可调用任何含有T类型参数的函数):

               Holder<? super Fruit> boundedHolder = appleHolder;   //ERROR

               boundedHolder = fruitHolder;

               boundedHolder.set(new Apple()); //

               boundedHolder.set(new Fruit());  //

       5)Holder<? super T >可合法指向Holder< T’s supclass >或Holder<T >。这个指向也是有代价的:禁止调用返回类型为T的函索(返回的对象类型得不到保证)。

               Holder<? super Fruit> boundedHolder = appleHolder;   //ERROR

               boundedHolder = fruitHolder;

               Fruit fruit = boundedHolder.get();         //ERROR

               Apple apple = (Apple) boundedHolder.get();//ERROR

    3、<?>

       1)无界通配符

       2)好像等价使用原生类型

       3)它仍然有价值:这是用泛型来编写代码,而不是使用原生类型,只是在当前情况下,泛型参数可以持有任何类型。

       4)Holder、Holder<?>和Holder<T>的区别

            Holder:表示“持有任何Object类型的原生Holder”

            Holder <?>:表示“持有某种类型的非原生Holder,该类型是Object或其子类”

            Holder <T>:表示“持有确切类型的非原生Holder”

      5)Holder<?>对象:禁止调用任何含有T类型参数的函数,并且调用返回类型为T的函索的返回值只能赋给Object。

           Holder<?> unboundedHolder = new Holder<?>)(new Apple());

           Object obj = unboundedHolder.get();

           unboundedHolder.set(new Apple());  //ERROR

      6)Holder与Holder<?>的本质区别:可用任意Object对象调用原始的Holder类的set()。

      7)尽管Holder<?>很脆弱,但Holder<?>仍然有它的作用,例如:判断Holder是否包含指定的对象不为空。

          public boolean hasNulls(Holder<?> h){

               return h.get() == null ||

          }

四、泛型继承及应用

    1、继承关系

    

    

    2、泛型类型与通配类型之间的继承关系(E为泛型类型参数,A为类或接口):

        ? super E :表示E的未知父类;? extends E:表示E的未知子类。

       

    3、应用举例

       1)E read(Holder<? extends E> holder){return holder.get();}

              Fruit f = meth(new Holder<Apple>(new Fruit()));

              Fruit a = meth(new Holder<Apple>(new Apple()));

       2)void write(Holder<? super E> holder, E item){ holder.set(item);}

              write(new Holder<Apple>, new Apple());  //Apple

              write(new Holder<Fruit>, new Apple());   //Apple的supclass