首页 > 学院 > 开发设计 > 正文

JAVA泛型——逆变

2019-11-14 15:14:59
字体:
来源:转载
供稿:网友

  在上篇《java泛型——协变》这篇文章中遗留以下问题——协变不能解决将子类型添加到父类型的泛型列表中。本篇将用逆变来解决这个问题。

实验准备

  我们首先增加以下方法,见代码清单1所示。

代码清单1

/**     *      * 描 述:Exp3使用逆变<br/>     * 作 者:jiaan.gja<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/>     * 作 者:jiaan.gja<br/>     * 历 史: (版本) 作者 时间 注释 <br/>     * @param itemList     */    public void addDecorate3(List<? super T> itemList, T t) {        itemList.add(t);    }

语法List<? super T>即为Java泛型的逆变,addDecorate3方法中的itemList.add(t)语句也没有协变出现的编译问题。

实验:泛型逆变

  现在我们尝试下逆变的用途,如代码清单2所示。

代码清单2

/** *  * 类 名: 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);        decoratorA.doDecorate3(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.addDecorate3(listB, tableOne);        decoratorB.addDecorate3(listB, tableTwo);        decoratorB.doDecorate3(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.addDecorate3(listC, serviceOne);        decoratorC.addDecorate3(listC, serviceTwo);        decoratorC.doDecorate3(listC);                /**         * 测试逆变开始         */        decoratorA.doDecorate3(listB);        decoratorA.doDecorate3(listC);            }}

 我们发现以下两条语句都会编译出错:

        decoratorA.doDecorate3(listB);        decoratorA.doDecorate3(listC);

我们暂且将这个问题放一放,将它们暂时注释掉,增加代码清单3中的代码。

代码清单3

        List<Object> listD = new ArrayList<Object>();                decoratorA.doDecorate3(listD);        decoratorA.doDecorate3(listA);        decoratorA.doDecorate3(listB);        decoratorA.doDecorate3(listC);        decoratorB.doDecorate3(listD);        decoratorB.doDecorate3(listA);        decoratorB.doDecorate3(listB);        decoratorB.doDecorate3(listC);        decoratorC.doDecorate3(listD);        decoratorC.doDecorate3(listA);        decoratorC.doDecorate3(listC);        decoratorC.doDecorate3(listB);    

 

代码清单3中,decoratorA.doDecorate3(listB);decoratorA.doDecorate3(listC);decoratorB.doDecorate3(listC);decoratorC.doDecorate3(listB);这四条语句编译错误,这说明如下声明是允许的:

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 = listA;        Object o = itemList.get(0);        Auction a = itemList.get(0);        Table t = itemList.get(0);        Service s = itemList.get(0);        itemList = listD;        o = itemList.get(0);        a = itemList.get(0);        t = itemList.get(0);        s = itemList.get(0);    

上述代码中,除了从itemList获取Object的语句之外,都会编译出错,这是为什么?因为itemList有可能是一个ArrayList<Object>,所以转型为Auction是可能错误的。itemList可能是ArrayList<Object>或者ArrayList<Auction>,所以转型为Table或者Service必然是不对的。

最后我们增加以下代码:

        itemList.add(new Auction("auctionThr"));        itemList.add(new Service("serviceThr", "methodThr"));        itemList.add(new Table("tableThr", 10));

上述代码没有问题,因为不论itemList是ArrayList<Object>或者ArrayList<Auction>,向其中添加Auction、Table、Service都符合最初的原则。

假如向itemList添加Object是编译失败的,因为itemList可能是ArrayList<Auction>。

总结

如果向泛型中添加子类,可以使用逆变来实现。如果要从泛型中获取子类,逆变有转型错误,此时应该使用协变。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表