JAVA泛型——协变
在上篇《JAVA泛型——基本使用》这篇文章中遗留以下问题,即将子类型Table或者也能添加到父类型Auction的泛型中,要实现这种功能必须借助于协变。
实验准备
现在在《JAVA泛型——基本使用》一文展示的Decorator类型的基础上,增加一些代码,如代码清单1所示。
代码清单1

/**
*
* 描 述:Exp2使用br/>
* 作 者:jiaan.gja<br/>
* 历 史: (版本) 作者 时间 注释 <br/>
* @param itemList
*/
public void doDecorate2(List<? extends T> itemList) {
for(int i = 0; i < itemList.size(); i++) {
System.out.println(itemList.get(i));
}
} /**
*
* 描 述:Exp2使用<br/>
* 作 者:jiaan.gja<br/>
* 历 史: (版本) 作者 时间 注释 <br/>
* @param itemList
* @param t
*/
public void addDecorate2(List<? extends T> itemList, T t) {
// itemList.add(t);
}

可以看到这跟《JAVA泛型——基本使用》中的doDecorate和addDecorate方法几乎一样,唯一的区别是将List<T>改为List<? extends T>,这种语法被称为协变。如果你已经在IDE里写了上面的代码,肯定发现addDecorate2中的语句itemList.add(t);已经编译报错。所以我们先将itemList.add(t);这条语句暂时注释掉,先来看看doDecorate2有没有达到我们的预期。
实验:泛型协变
现在我们看看协变的用途,即调用doDecorate2方法,如代码清单2所示。
代码清单2

/**
*
* 类 名: Exp2<br/>
* 描 述: 泛型的协变使用<br/>
* 作 者: jiaan.gja<br/>
* 创 建: 2015年8月20日<br/>
*
* 历 史: (版本) 作者 时间 注释
*/
class Exp2 {
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.addDecorate2(listA, auctionOne);
decoratorA.addDecorate2(listA, auctionTwo);
decoratorA.doDecorate2(listA); 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.addDecorate2(listB, tableOne);
decoratorB.addDecorate2(listB, tableTwo);
decoratorB.doDecorate2(listB); 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.addDecorate2(listC, serviceOne);
decoratorC.addDecorate2(listC, serviceTwo);
decoratorC.doDecorate2(listC); /*
* 协变测试开始
*/
decoratorA.doDecorate2(listB);
decoratorA.doDecorate2(listC); }
}

首先,我们看到doDecorate2方法至少能达到《JAVA泛型——基本使用》文中的doDecorate方法的效果。
由于声明了decoratorA的类型是Decorator<Auction>,那么此时实例decoratorA的doDecorate2方法的参数可以认为是下面这样:
List<? extends Auction> itemList
而listB的类型是ArrayList<Table>,listC的类型是ArrayList<Service>,也就是说协变允许:
List<? extends Auction> itemList = new ArrayList<Auction>();
List<? extends Auction> itemList = new ArrayList<Table>();
List<? extends Auction> itemList = new ArrayList<Service>();
这说明itemList中既可以存储Auction,也可以存储Table和Service。我们做个假设,当你想从itemList中获取Table的时候,Java编译器怀疑这实际可能是个Service,因此会有编译错误。如果想从itemList中获取Auction是没有问题的,因为无论是Table还是Service它们都可以被自动转换为父类Auction。这些推测,可以通过代码清单3验证。
代码清单3

List<? extends Auction> itemList = listA;
Auction a = itemList.get(0);
Table t = itemList.get(0);
Service s = itemList.get(0);
itemList = listB;
a = itemList.get(0);
t = itemList.get(0);
s = itemList.get(0);
itemList = listC;
a = itemList.get(0);
t = itemList.get(0);
s = itemList.get(0);

同样的道理,当你想要向itemList中添加Table时,编译器怀疑itemList实际是个ArrayList<Service>,因此是不允许的。在获取Auction时是没有问题的,那么添加Auction会不会也可以?由于itemList可能是ArrayList<Service>或者ArrayList<Table>,根据上一篇《JAVA泛型——基本使用》的结论,这实际也是不可以的。可以用下列代码验证:
        Auction auctionThree = new Auction("auctionThree");
        itemList.add(auctionThree);
        Auction tableThree = new Auction("tableThree");
        itemList.add(tableThree);
        Auction serviceThree = new Auction("serviceThree");
        itemList.add(serviceThree);
因此这也说明了刚开始看到的addDecorate2中的语句itemList.add(t);为什么会编译报错。虽然如此,我们依然希望能将子类型添加到父类型声明的泛型中,这该怎么办?Java当然也考虑到这个问题,请看下一篇《JAVA泛型——逆变》。
总结
如果从泛型中获取子类,应该使用协变。
如需转载,请标明本文作者及出处——作者:jiaan.gja,本文原创首发:博客园,原文链接:http://www.cnblogs.com/jiaan-geng/p/4916347.html
JAVA泛型——协变的更多相关文章
- JAVA泛型——逆变
		
在上篇<JAVA泛型——协变>这篇文章中遗留以下问题——协变不能解决将子类型添加到父类型的泛型列表中.本篇将用逆变来解决这个问题. 实验准备 我们首先增加以下方法,见代码清单1所示. 代码 ...
 - JAVA泛型——基本使用
		
Java1.5版本推出了泛型,虽然这层语法糖给开发人员带来了代码复用性方面的提升,但是这不过是编译器所做的一层语法糖,在真正生成的字节码中,这类信息却被擦除了.笔者发现很多几年开发经验的程序员,依然不 ...
 - Java泛型的协变
		
在上篇<Java泛型的基本使用>这篇文章中遗留以下问题,即将子类型也能添加到父类型的泛型中,要实现这种功能必须借助于协变. 实验准备 现在在上篇文章展示的Decorator类型的基础上,增 ...
 - Java泛型中的协变和逆变
		
Java泛型中的协变和逆变 一般我们看Java泛型好像是不支持协变或逆变的,比如前面提到的List<Object>和List<String>之间是不可变的.但当我们在Java泛 ...
 - Java泛型的协变与逆变
		
泛型擦除 Java的泛型本质上不是真正的泛型,而是利用了类型擦除(type erasure),比如下面的代码就会出现错误: 报的错误是:both methods have same erasure ...
 - 初识java泛型
		
1 协变数组类型(covariant array type) 数组的协变性: if A IS-A B then A[] IS-A B[] 也就是说,java中的数组兼容,一个类型的数组兼容他的子类类型 ...
 - 【Java心得总结四】Java泛型下——万恶的擦除
		
一.万恶的擦除 我在自己总结的[Java心得总结三]Java泛型上——初识泛型这篇博文中提到了Java中对泛型擦除的问题,考虑下面代码: import java.util.*; public clas ...
 - Java泛型-内部原理: 类型擦除以及类型擦除带来的问题
		
一:Java泛型的实现方法:类型擦除 大家都知道,Java的泛型是伪泛型,这是因为Java在编译期间,所有的泛型信息都会被擦掉,正确理解泛型概念的首要前提是理解类型擦除.Java的泛型基本上都是在编译 ...
 - Java泛型-类型擦除
		
一.概述 Java泛型在使用过程有诸多的问题,如不存在List<String>.class, List<Integer>不能赋值给List<Number>(不可协变 ...
 
随机推荐
- (zxing.net)二维码QR Code的简介、实现与解码
			
一.简介 二维码QR Code(Quick Response Code)是由Denso公司于1994年9月研制的一种矩阵二维码符号,它具有一维条码及其它二维条码所具有的信息容量大.可靠性高.可表示汉字 ...
 - WindowsPhone模拟简易Toast弹出框
			
Coding4Fun这个开源控件中有ToastPrompt这个弹出框组件,但是由于Coding4Fun太庞大,如果只用到ToastPrompt这个控件的话,整个引用不太值当的.于是自己写了一个差不多的 ...
 - js实现window.open不被拦截的解决方法汇总
			
一.问题: 今天在处理页面ajax请求过程中,想实现请求后打开新页面,就想到通过 js window.open 来实现,但是最终都被浏览器拦截了. 二.分析: 在谷歌搜索有没有解决方法,有些说可以通过 ...
 - c++11新特性总结(转。加上重点)
			
1.类型与变量相关 1.1.nullptr: 取代了NULL,专用于空指针 1.2.constexpr: 近似const, 可以修饰变量,也可以修饰函数, 修饰变量如: const int globa ...
 - 【文文殿下】快速傅里叶变换(FFT)学习笔记
			
多项式 定义 形如\(A(x)=\sum_{i=0}^{n-1} a_i x^i\)的式子称为多项式. 我们把\(n\)称为该多项式的次数界. 显然,一个\(n-1\)次多项式的次数界为\(n\). ...
 - BZOJ 1801--中国象棋(DP)
			
1801: [Ahoi2009]chess 中国象棋 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1995 Solved: 1160[Submit] ...
 - Elasticsearch5.4 删除type
			
首先要说明的是现在的Elasticsearch已经不支持删除一个type了,所以使用delete命令想要尝试删除一个type的时候会出现如下错误,如果存在一个名为edemo的index和tets的ty ...
 - day06  --class --home
			
# -*- coding: utf-8 -*-# @Time : 2018/12/26 20:29# @Author : Endless-cloud# @Site : # @File : day 06 ...
 - Swagger2使用记录
			
1. Swagger2使用记录 1.1. Bean配置文件 @Configuration public class Swagger2 { @Bean public Docket createRestA ...
 - redis-server.exe双击闪退 win10系统
			
博客 解决方法: 1-win+R 打开命令行 2-cd至redis目录,例如 D:\redis> 3-输入 redis-server.exe redis.windows.conf 4-若 ...