java泛型通配符

泛型 generics
协变 co-variant
逆变 Contra-variance
通配符类型 wildcard type

数组是协变的

我们可以把一个dog的数组,赋值给Pet数组,因为Pet是Dog的基类。

Dog[] dogs = { new Dog() };
Pet[] pets = dogs;

在pets这里,他已经不知道数组里的内容是Dog了,他可能会执行如下操作。

pets[0] = new Cat();

这个时候编译是没问题的,但是运行会报错,抛出ArrayStoreException
java的数组是协变的(简单说可以把子类数组赋给父类),但是这是不安全的,可能会引起运行时问题。

java泛型

java1.5版本引入了泛型概念,由于数组协变带来了不安全,所以泛型设计的时候是不支持协变的,这样把运行时的问题提早到了编译时,提高了代码的安全性。

List<Dog> dogs = new ArrayList<Dog>();
List<Pet> pet = dogs; // This line does not compile

现在List和List两者是不同的类型,没有办法直接赋值,虽然保护了安全性,但是带来了新的问题。如下方法是给List准备的,但是List却不能使用,这多少有点违反直觉,毕竟Dog是Pet的子类。

  public void feed(List<Pet> pet){
  }

基于这个问题,出现了extend通配符

extend通配符

使用? extends Pet就可以解决上述问题。这样似乎又变成协变的了。? extends Pet表示这里有个类型,他一定是Pet的子类,但是具体是什么类型我们不关心。

    public void feed(List<? extends Pet> pets){
    }

协变的话,会不会产生数组的那种问题呢?,试试看如下代码


    public void feed(List<? extends Pet> pets){
        pets.add(new Cat());
    }

编译时直接报错了
在这里插入图片描述
对于extend通配符,语法层面只允许读,不允许写,读的话我们保证能拿到一个Pet类型的数据,禁止写保证了运行时安全。

    public void feed(List<? extends Pet> pets){
        pets.add(new Cat());//compile error
        pets.get(0);  //ok
    }

super通配符

对于的出现了super通配符,他保证这个类是Pet的父类,只允许写,不允许读。

List<Pet> pets = new ArrayList<Pet>();
List<? super Pet> contravariantList = pets;
Pet pet = contravariantList.get(0); // This does not compile.
contravariantList.add(new Pet()); // OK

总结

这就是目前java的通配符机制

extend通配符要求是X的子类只允许读,不允许写
super通配符要求是X的父类只允许写,不允许读

ref

https://advancedweb.hu/using-java-generics-to-express-variance-of-collections-and-functions/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值