java 泛型通配符与super、extends使用的相关问题原理

22 篇文章 0 订阅
class A{}
class B extends A{}
class C extends B{}
class D extends C{}
class E extends D{}

一、  super,读和写数据都支持。

(1)写数据时要写下界或者下界类型的子类,这里是C或者C的子类。

(2)读数据时获取的只能是Object的对象,要自己把该对象强制转换为自己的类型。。不过获取数据时一般不知道具体类型是什么,只能确定获取出来的对象一定是下界类型或者下界类型的子类(C或者C的子类)

        List<A> list = new ArrayList<>();
        list.add(a);
        list.add(b);
        list.add(c);
        
        List<? super C> param  = list;
        //(1)此时编译器只能判断出param这个list的元素类型都是C或者C的超类。
        //(2)param调用add方法时,编译器只能确定param是一定能把C以及C的子类的实例添加进去的。
        // 根据(1)可知,param可能是List<A>也可能是List<B>以及其他可能,
        //如果param是List<A>那还好,ABCDE的实例都能加,但是如果param是List<B>,
        //然后想要param.add(a),这个时候肯定是不行的。。所以,编译器无法预知这些东西,只能确定一定能把C以及C的子类的实例添加进去不会有任何问题。

//        param.add(new B());// ERROR
//        param.add(new Object());//ERROR
        param.add(new D());//right
        param.add(new E());//right

        C c = (C)param.get(0);//right

原理:

二、extends,只能读数据,写数据只能传null,不能传其他类型。读数据时会自动转为

   
    List<D> list=new ArrayList<>();
    list.add(...);
    list.add(...);
    List<? extends C> param  = list;
//        param.add(new B());// ERROR
//        param.add(new Object());//ERROR
    
    //上界是C类型,自然AB都无法添加,
    //而编译器也无法知道param的元素类型是C还是D还是E,所以添加元素也是不可行的。
    //原因:假设param的实际类型是List<D>,
    //param.add(c)和param.add(e)该怎么处理?
    //其中,e是D的子类实例,正常来讲是可以添加成功的,但是程序在运行时传进来的list是什么类型只有运行时才能知道啊
    //语法上只能确保param的实际类型一定是C或者C的子类,无法param的元素类型是C的哪个子类。。
    //所以当运行时传进来的list是D类型的,然后我们一定要运行param.add(c),那肯定是不行的。
    //有人说指定执行param.add(d)或者param.add(e)不就行了?那么,问个问题,
    //如何保证param的元素类型一定是D,万一运行时传进来的是List<E>呢,那这个时候param.add(d)就错了。
    //所以,基于这种无法预知的情况,就只能禁止添加了。。。
    //那么null为什么可以呢,emm,任何一个类型的的变量不都可以为null么,那自然是可以的。。
    //除非能找到一种类型,是任何情况下已知类型的子类型,这样的话这个类型的实例就和null一样都可以添加。但java没有这样的东西,scala倒是有。


    //获取是可以确定类型的,这个没毛病。
    //因为param的元素类型一定是C或者C的子类型,那么全部都一定可以向上转型为C类型。。

    param.add(null);
    C c1 = param.get(0);

 

 

下面的是以前的理解,可以忽略

//***************************************

public void test(List<? extends Number> list) {
        // 在该方法中只能知道list的参数类型是Number的子类,但并不知道具体是哪个子类
        // 所以,不能在该方法中往list添加数据
        // 假设,别人调用该test方法,传进来的list是List<Integer>类型的,
        // 如果在该test方法中允许往list添加数据,那么,写这个test方法的只能知道list的元素类型是Number及其子类
        // 只要往list中添加了Number及其子类类型不是Integer类型,那么岂不是导致外部传进来的
        // List<Integer> list的某个元素变成非Integer类型的。。。这肯定不行
    }

    public void test2(List<? super Integer> list) {
        // 在该方法中只能知道List的参数类型是Integer及其父类,但并不知道具体是哪个父类
        // 所以,该方法的编写者获取list的元素的类型,只能确定一定是Object的子类,所以返回类型为Object是绝对没问题的。
        // 当外部调用者调用该test2方法时,传进来的list的参数类型只能是Integer及其父类型,
        // 那么,作为test2方法的编写者,往list里添加设置数据时,添加的是Integer类型及其子类型时肯定不会出现类型转换错误
        // 因为外部传进来的list的元素类型只能是Integer及其父类型。
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值