Java泛型的逆变

简介: 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/beliefer/article/details/50953198 实验准备...
版权声明:本文为博主原创文章,未经博主允许不得转载。 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>。
相关文章
|
8天前
|
JavaScript Java 编译器
Java包装类和泛型的知识点详解
Java包装类和泛型的知识点的深度理解
|
29天前
|
Java
java中的泛型类型擦除
java中的泛型类型擦除
13 2
|
1月前
|
存储 Java fastjson
Java泛型-4(类型擦除后如何获取泛型参数)
Java泛型-4(类型擦除后如何获取泛型参数)
33 1
|
7天前
|
存储 监控 安全
泛型魔法:解码Java中的类型参数
泛型魔法:解码Java中的类型参数
30 0
泛型魔法:解码Java中的类型参数
|
9天前
|
Java API
Java基础—笔记—内部类、枚举、泛型篇
本文介绍了Java编程中的内部类、枚举和泛型概念。匿名内部类用于简化类的创建,常作为方法参数,其原理是生成一个隐含的子类。枚举用于表示有限的固定数量的值,常用于系统配置或switch语句中。泛型则用来在编译时增强类型安全性,接收特定数据类型,包括泛型类、泛型接口和泛型方法。
9 0
|
1月前
|
存储 安全 Java
JAVA泛型
JAVA泛型
11 0
|
1月前
|
Java 编译器
[java进阶]——泛型类、泛型方法、泛型接口、泛型的通配符
[java进阶]——泛型类、泛型方法、泛型接口、泛型的通配符
|
1月前
|
存储 Java 编译器
Java——泛型
Java——泛型
15 0
|
1月前
|
存储 安全 Java
JAVA的泛型
JAVA的泛型
9 0
|
2月前
|
算法 Java 编译器
重学Java之泛型的基本使用
重学Java之泛型的基本使用