【翻译】Java泛型中的extends与super

本文深入解析Java泛型中<?extendsT>与<?superT>的使用差异,通过具体示例说明两者在容器读写操作中的表现,并提供PECS规则指导正确应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在Java泛型中常用的通配符有两种

  • <? extends T> 设置参数化类型的上界,表示参数化类型只能是T、T的子类或实现类。

  • <? super T> 设置参数化类型的下界,表示参数化类型只能是T或T的父类。

泛型的通配符常使用在容器中,下面来辨析以上两种通配符在容器中使用时的差异。

#一 <? extends T>

List<? extends Number> foo3 = new ArrayList<Number>();
List<? extends Number> foo3 = new ArrayList<Integer>();
List<? extends Number> foo3 = new ArrayList<Double>();

##1.从List中读取

  • 可以从foo3中读取出Number类型,因为右边的泛型参数都是Number的子类。
  • 无法从foo3中读取出Integer类型,因为foo3可能是对ArrayList<Double>的引用。
  • 无法从foo3中读取出Double类型,因为foo3可能是对ArrayList<Integer>的引用。

##2.写入List

  • 无法写入Number类型,因为foo3可能是List<Double>或List<Integer>。
  • 无法写入Integer类型,因为foo3可能是List<Double>或List<Number>。
  • 无法写入Double类型,因为foo3可能是List<Integer>或List<Number>。

实际上你无法像向foo3中写入任何类型,因为无法确定foo3的实际类型。你能确保的是,从foo3中读取出的对象一定是Number或Number的子类。

#二 <? super T>

List<? super Integer> foo3 = new ArrayList<Integer>();
List<? super Integer> foo3 = new ArrayList<Number>();
List<? super Integer> foo3 = new ArrayList<Object>();

##1.从List中读取

  • 无法读取Integer类型,因为foo3可能是List<Number>或List<Object>。
  • 无法读取Number类型,因为foo3可能是List<Object>。
  • 只能读取Object类型,因为foo3中的内容是Object或者是Object的子类。

##2.写入List

  • 可以写入Integer与Integer的子类,因为它们都是Number,Object的子类。
  • 无法写入Double类,因为foo3可能是List<Integer>。
  • 无法写入Number类,因为foo3可能是List<Integer>。
  • 无法写入Object类,因为foo3可能是List<Integer>。

在使用extends与super时,可参照PECS("Producer Extends, Consumer Super")规则:

  • "Producer Extends" 如果容器的作用是用来生产某个对象(从容器中取出某个类型的对象),那么就应该用 <? extends T>。
  • "Consumer Super" 如果容器的作用是用来消费某个对象(向容器中放置某个类型的对象),那么就应该使用<? super T>。
  • 如果需要同时取出与存放某个类型的对象,那么就应该明确指明对象,例如List<Integer>

原文:Difference between <? super T> and <? extends T> in Java

转载于:https://my.oschina.net/u/189332/blog/551980

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值