黑马程序员: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