【Java通配符】有限制的(上限、下限)通配符--向有限制通配符声明的集合中插入对象测试

Java中有限制的(上限、下限)通配符–向有限制通配符声明的集合中插入对象测试

学习通配符时,基于https://www.codenong.com/44516990/的例子,遇到了一些问题,做了编译测试并在测试基础上得出结论。

结论:

测试1、2、5对使用有限制的通配符的集合声明进行了测试,得出结论:使用通配符进行集合的声明便不要插入对象,这个时候编译器由于实现的是伪泛型会进行泛型擦除,最终把? super Sparrow替换成Sparrow。

测试3、4分别对集合的声明和定义以及作为方法参数的调用进行了测试,均符合预期效果。

测试用例关系如下:

此处直接使用java自带的泛型类List进行测试。
注意:四者无关系

测试代码如下:


import java.util.ArrayList;
import java.util.List;

/**
 * @author hyg
 * @create 2021-07-02-21:39
 */
public class Birds {
    static class Bird{}
    static class Sparrow extends Bird{}
    static class Color extends Bird{}
    static class Color1 extends Sparrow{}


    public static void main(String[] args){
//========编译测试1:<? extends Bird> 的列表中添加新对象======================================================================================
        List<? extends Bird> birds = new ArrayList<Bird>();
        birds.add(new Sparrow()); // #1 DOES NOT COMPILE
        birds.add(new Bird());// #2 DOES NOT COMPILE
        birds.get(0);// CAN COMPILE
//        编译错误原因:这里的 <? extends Bird> 只表示 任何一个Bird的子类 ,而不是所有的子类。重点在于一个类。
//        所以这个时候有可能是任何类,所以 <? extends Bird> 不能用add,只能get。即只能读不能写。
//        倘若需要add,则用super,如编译测试2所示。

//========编译测试2:<? super Bird> 的列表中添加新对象========================================================================================
        List<? super Sparrow> birds = new ArrayList<>();
        birds.add(new Sparrow()); // CAN COMPILE
        birds.add(new Bird());// DOES NOT COMPILE   这里不能编译,因为<? super Sparrow>代表该list的泛型类型的范围是 Sparrow类及其父类, 再根据子类可以
        birds.add(new Color());// DOES NOT COMPILE
        birds.add(new Color1());// CAN COMPILE
        System.out.println(birds.get(0));
        System.out.println(birds.get(1));

//========编译测试3:有限制通配符最常用方法,符合super语义以及正常使用的一种===============================================================================
        List<? super Sparrow> birds = null;
        List<Bird> bird = new ArrayList<>();
        List<Sparrow> sparrow = new ArrayList<>();
        List<Color> color = new ArrayList<>();
        List<Color1> color1 = new ArrayList<>();
        birds = bird;// CAN COMPILE
        birds = sparrow;// CAN COMPILE
        birds = color;// DOES NOT COMPILE
        birds = color1;// DOES NOT COMPILE
//        编译错误原因:<? super Sparrow> 表示的是Sparrow本身及其超类,这里只有Bird和Sparrow符合要求,Color和Color1不符合要求。

//========编译测试4:有限制通配符作为方法参数与泛型作为方法参数的对比===========================================================================
//--------------------------------------------1----------------------------
        List<Sparrow> birds1 = new ArrayList<>();
        birds1.add(new Sparrow());
        birds1.add(new Color1());
        callGenericParams(birds1);
        callWildcardParams(birds1);
        //Output:
        //QuestionMark.Birds$Sparrow@1b6d3586
        //QuestionMark.Birds$Color1@4554617c
        //QuestionMark.Birds$Sparrow@1b6d3586
        //QuestionMark.Birds$Color1@4554617c

//--------------------------------------------2----------------------------
        List<Bird> birds2 = new ArrayList<>();
        birds3.add(new Sparrow());
        birds3.add(new Color1());
        callWildcardParams(birds3);// DOES NOT COMPILE: 方法仅接受Sparrow及其子类,Bird不在范围内

//--------------------------------------------3----------------------------
        List<Color1> birds3 = new ArrayList<>();
//        birds4.add(new Sparrow());// DOES NOT COMPILE: 因为bird3这个List中存放子类Color及Color得子类的对象(普通多态)。这里的编译结果与测试2中
                                    // <? super Sparrow> 的结果相同,进一步肯定了类型擦除时,编译器将<? super Sparrow> 替换为 <Sparrow>,所以往里
                                    //面插入对象的时候只可以add Sparrow的对象以及Sparrow子类的对象。  测试5中进行完整对比测试。
        birds3.add(new Color1());
        birds3.add(new Color1());
        callGenericParams(birds3);
        callWildcardParams(birds3);
        //Output:
        //QuestionMark.Birds$Color1@74a14482
        //QuestionMark.Birds$Color1@1540e19d
        //QuestionMark.Birds$Color1@74a14482
        //QuestionMark.Birds$Color1@1540e19d
		
//		callGenericParams()和callWildcardParams()两个方法分别使用通配符和泛型声明,但效果相同。

//========编译测试5:往有限制通配符声明的集合中插入对象,编译器实际编译情况======================================================================
        List<? super Sparrow> birds = new ArrayList<>();
        birds.add(new Sparrow()); // CAN COMPILE
        birds.add(new Bird());// DOES NOT COMPILE
        birds.add(new Color());// DOES NOT COMPILE
        birds.add(new Color1());// CAN COMPILE

        List<Sparrow> sparrows = new ArrayList<>();
        birds.add(new Sparrow()); // CAN COMPILE
        birds.add(new Bird());// DOES NOT COMPILE
        birds.add(new Color());// DOES NOT COMPILE
        birds.add(new Color1());// CAN COMPILE

        //根据上面编译情况可以看到两种声明 List<Sparrow>和List<? super Sparrow> 编译效果相同,实际上如果想要声明集合并插入对象时,使用有限的通配符,编译器
        //是无法理解的,只能直接理解为super之后的对象,并按照普通的泛型Sparrow来进行声明和定义。
        //结论:使用通配符基本上是使用在方法参数里面,或者普通的声明而不插入对象。 要插入对象就不用使用通配符。
    }


    //下面两个方法声明效果相同。
    public static void callWildcardParams(List<? extends Sparrow> birds){
        System.out.println(birds.get(0));
        System.out.println(birds.get(1));
    }
    public static <E extends Sparrow> void callGenericParams(List<E> birds){
        System.out.println(birds.get(0));
        System.out.println(birds.get(1));
    }
}

如有纰漏请提出,共同学习,谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值