Java泛型的逆变

版权声明:本文为博主原创文章,未经博主允许不得转载。 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>。
上一篇:spark2.1.0之源码分析——服务端RPC处理器RpcHandler详解


下一篇:Tomcat7.0源码分析——server.xml文件的加载与解析