Java 泛型 PECS

在stackoverflow上看到两篇关于java泛型 PECS 的问答:

  1. Difference between and in java
  2. How can I add to List data structures

PECS

Remember PECS:"Producer Extends,Consumer Super"

  • "Producer Extends" - If you need a List to produce T values (you want to read Ts from the list), you need to declare it with ? extends T, e.g. List. But you cannot add to this list.

  • "Consumer Super" - If you need a List to consume T values (you want to write Ts into the list), you need to declare it with ? super T, e.g. List. But there are no guarantees what type of object you may read from this list.

  • If you need to both read from and write to a list, you need to declare it exactly with no wildcards, e.g. List.

也就是说:

  • 当你仅仅需要从List中读出T,那么你需要使用? extends T.例如List
  • 当你仅仅需要将T写入List时,那么你需要使用? super T.例如List
  • 当你既需要读也需要写时,你应该直接使用T. List< Integer>

PECS的使用

extends

List foo 表示foo可以存储一族的类型的值(而不是一个特殊的类型的值),所以下面的声明都是正确的:

List foo = new ArrayList;  // Number "extends" Number
List foo = new ArrayList; // Integer extends Number
List foo = new ArrayList;  // Double extends Number

正因为foo表示存储的是一族的类型的值,无法保证具体指向的类型,所以我们无法保证我们add的对象是List允许的类型。假如我们add一个Integer的值,但是foo可能指向Double(第三条语句),我们add一个Double的值,foo可能指向Integer(第二条语句)。

虽然无法add,但是我们可以保证我们从foo中取出来的值肯定是属于Number或者是Number的子类,所以我们可以从foo中获取值。

super

关于List,以下声明是正确的:

List foo = new ArrayList; // Number is a "super" of Number
List foo = new ArrayList; // Object is a "super" of Number

因为foo的类型无法确定,可能是Number,也可能是Number的父类,我们无法保证读出来的值的类型,所以无法从List中读出值。但是我们可以保证我们插进去的值肯定属于Number或者Number的父类,因此我们可以使用add

JDK中的例子

Collections.copy()的方法签名:

public static  void copy(List dest,List src)

src中,我们可以传入与T类型相关的List,并且能够保证取出的是T类型或者T的子类型的值。

dest中,我们可以传入T类型和T的父类的List,并且能够保证我们从存放的值都满足要求。

例如:

// copy(dest, src)
Collections.copy(new ArrayList(), new ArrayList(), new ArrayList(), new ArrayList());
Collections.copy(new ArrayList(), new ArrayList

有兴趣的同学可以去看原文。

你可能感兴趣的:(Java 泛型 PECS)