版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/beliefer/article/details/50953198
实验准备
在上篇《Java泛型的协变》这篇文章中遗留以下问题:将子类型添加到父类型的泛型时发现,协变不能解决向泛型列表中添加元素的问题,现在我们增加如下代码:
/**
*
* 描 述:Exp3使用<br/>
* 作 者:耿嘉安<br/>
* 历 史: (版本) 作者 时间 注释 <br/>
* @param itemList
*/
public void doDecorate3(List<? super T> itemList, T t) {
for(int i = 0; i < itemList.size(); i++) {
System.out.println(itemList.get(i));
}
}
/**
*
* 描 述:Exp3使用<br/>
* 作 者:耿嘉安<br/>
* 历 史: (版本) 作者 时间 注释 <br/>
* @param itemList
*/
public void addDecorate3(List<? super T> itemList, T t) {
itemList.add(t);
}
可以看到我们使用List<? super T>的语法,即逆变声明了doDecorate3和addDecorate3的参数。我们先来看addDecorate3,当调用itemList.add(t)语句时已经没有了编译错误,下面我们看看doDecorate3和addDecorate3的使用。
实验三:泛型逆变
现在我们尝试下逆变的用途,代码如下:
/**
*
* 类 名: Exp3<br/>
* 描 述: 泛型的逆变使用<br/>
* 作 者: 耿嘉安<br/>
* 创 建: 2015年8月25日<br/>
*
* 历 史: (版本) 作者 时间 注释
*/
class Exp3 {
public static void main(String[] args) {
Decorator<Auction> decoratorA = new Decorator<Auction>();
List<Auction> listA = new ArrayList<Auction>();
Auction auctionOne = new Auction("auctionOne");
Auction auctionTwo = new Auction("auctionTwo");
decoratorA.addDecorate3(listA, auctionOne);
decoratorA.addDecorate3(listA, auctionTwo);
Decorator<Table> decoratorB = new Decorator<Table>();
List<Table> listB = new ArrayList<Table>();
Table tableOne = new Table("tableOne", 10);
Table tableTwo = new Table("tableTwo", 20);
decoratorB.addDecorate3(listB, tableOne);
decoratorB.addDecorate3(listB, tableTwo);
Decorator<Service> decoratorC = new Decorator<Service>();
List<Service> listC = new ArrayList<Service>();
Service serviceOne = new Service("serviceOne", "methodOne");
Service serviceTwo = new Service("serviceTwo", "methodTwo");
decoratorC.addDecorate3(listC, serviceOne);
decoratorC.addDecorate3(listC, serviceTwo);
decoratorA.doDecorate3(listD, new Auction("auctionThr"));
decoratorA.doDecorate3(listA, new Auction("auctionThr"));
decoratorA.doDecorate3(listB, new Table("tableThr", 10));
decoratorA.doDecorate3(listC, new Service("serviceThr", "methodThr"));
decoratorB.doDecorate3(listA, new Table("tableThr", 10));
decoratorB.doDecorate3(listD, new Table("tableThr", 10));
decoratorB.doDecorate3(listB, new Table("tableThr", 10));
decoratorB.doDecorate3(listC, new Table("tableThr", 10));
decoratorC.doDecorate3(listA, new Service("serviceThr", "methodThr"));
decoratorC.doDecorate3(listD, new Service("serviceThr", "methodThr"));
decoratorC.doDecorate3(listC, new Service("serviceThr", "methodThr"));
decoratorC.doDecorate3(listB, new Service("serviceThr", "methodThr"));
}
}
我们看到addDecorate3编译正常,但是部分doDecorate3反而编译出错了,这说明这样如下的声明是允许的:
List<? super Auction> itemList = new ArrayList<Object>();
List<? super Auction> itemList = new ArrayList<Auction>();
List<? super Table> itemList = new ArrayList<Object>();
List<? super Table> itemList = new ArrayList<Auction>();
List<? super Table> itemList = new ArrayList<Table>();
List<? super Service> itemList = new ArrayList<Object>();
List<? super Service> itemList = new ArrayList<Auction>();
List<? super Service> itemList = new ArrayList<Service>();
而下面这样是不允许的:
List<? super Auction> itemList = new ArrayList<Table>();
List<? super Auction> itemList = new ArrayList<Service>();
List<? super Table> itemList = new ArrayList<Service>();
List<? super Service> itemList = new ArrayList<Table>();
最后回头看看下面的例子:
List<? super Auction> itemList = new ArrayList<Auction>();
Auction auction = itemList.get(0);
Service service = itemList.get(0);
Table table = itemList.get(0);
Object obj = itemList.get(0);
itemList.add(new Auction("auctionThr"));
itemList.add(new Service("serviceThr", "methodThr"));
itemList.add(new Table("tableThr", 10));
我们发现除了能够从itemList中获取Object之外,其余类型都不可以,这是为什么?因为itemList有可能是一个ArrayList<Object>,所以转型为Auction是可能错误的。itemList可能是ArrayList<Object>或者ArrayList<Auction>,所以转型为Table或者Service必然是不对的。最后我们看到不论itemList是ArrayList<Object>或者ArrayList<Auction>,向其中添加Auction、Table、Service都符合最初的原则。假如向itemList添加Object是编译失败的,因为itemList可能是ArrayList<Auction>。