泛型中extends和super的区别

extends

通配符式声明 List<? extends Number> foo3 意味着以下每一条皆为合法语句:

List<? extends Number> foo3 = new ArrayList<Number>();  // Number "extends" Number (in this context)
List<? extends Number> foo3 = new ArrayList<Integer>(); // Integer extends Number
List<? extends Number> foo3 = new ArrayList<Double>();  // Double extends Number
  1. - 若有以上声明,则对List foo3进行读操作时会出现以下情形:
    • 可以读取Number类型的数据,因为可以赋予foos的列表均包含Number类型或其子类型的数据。
    • 无法读取Integer类型的数据,因为foo3可能指向List<Double>类型的数据。
    • 无法读取Double类型的数据,因为foo3可能指向List<Integer>类型的数据。
  2. - 若有以上声明,则对List foo3进行写操作(add)时会出现以下情形:
    • 无法增添Integer类型的数据,因为foo3可能指向List<Double>类型的数据。
    • 无法增添Double类型的数据,因为foo3可能指向List<Integer>类型的数据。
    • 无法增添Number类型的数据,因为foo3可能指向List<Integer>类型的数据。

无法向List<? extends T>添加任何对象,因为无法保证变量具体指向的是什么类型的List,从而无法保证目标List允许添加何种类型的对象。唯一能保证的是可以从中读出一个T类型或其子类型的数据。

super

List <? super T>.

通配符式声明 List<? super Integer> foo3 意味着以下每一条皆为合法语句:

List<? super Integer> foo3 = new ArrayList<Integer>();  // Integer is a "superclass" of Integer (in this context)
List<? super Integer> foo3 = new ArrayList<Number>();   // Number is a superclass of Integer
List<? super Integer> foo3 = new ArrayList<Object>();   // Object is a superclass of Integer
  1. - 若有以上声明,则对List foo3进行读操作时会出现以下情形:
    • 无法读取Integer类型的数据,因为foo3可能指向List<Number>List<Object>类型的数据。
    • 无法读取Number类型的数据,因为foo3可能指向List<Object>类型的数据。
    • 只能读取Object类型或Object子类型的数据(但无法确定是那个子类)。
  2. - 若有以上声明,则对List foo3进行写操作(add)时会出现以下情形:
    • 可以增添Integer类型的数据,因为示例代码中的所有list均允许增添Integer类型的数据。
    • 可以增添Integer子类型的数据,因为示例代码中的所有list均允许增添Integer子类型的数据。
    • 无法增添Double类型的数据,因为foo3可能指向ArrayList<Integer>类型的数据。
    • 无法增添Number类型的数据,因为foo3可能指向ArrayList<Integer>类型的数据。
    • 无法增添Object类型的数据,因为foo3可能指向ArrayList<Integer>类型的数据。

PECS

记住一个口诀: "Producer Extends, Consumer Super"(PECS).

  • "Producer Extends" - 如果一个List需要生产T类型的数据(你想要从list中读取T类型数据),你需要将其声明成? extends T, e.g. List<? extends Integer>。但你无法向其中增添数据。
  • "Consumer Super" - 如果你需要一个消费T类型数据的list(向其中增添T类型数据),你需要将其声明成? super T, e.g. List<? super Integer>。但是你将不知道会从中读取到何种类型的数据。
  • 如果你需要从对List进行读和写操作,则不要使用通配符式的声明方式,e.g. List<Integer>

===> 翻译于StackOverflow

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。