`copy(List <?super T> dest,List <?extends T> src)`和`copy(List <T> dest,List <?extends T> src)之间的区别

Xin*_*Xin 8 java generics

我正在尝试通过阅读以下内容来学习Java Generics通配符:http: //www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#FAQ103

材料中有一个例子:

public class Collections { 
  public static <T> void copy (List<? super T> dest, List<? extends T> src) {
      for (int i=0; i<src.size(); i++) 
        dest.set(i,src.get(i)); 
  } 
}
Run Code Online (Sandbox Code Playgroud)

我想知道我是否可以更改方法签名如下:

  public static <T> void copy(List<? super T> dest, List<? extends T> src) {
Run Code Online (Sandbox Code Playgroud)

  public static <T> void copy(List<T> dest, List<? extends T> src) {
Run Code Online (Sandbox Code Playgroud)

这两种方法是否存在差异?

例子将不胜感激.

mat*_*ake 5

你是对的.在这种情况下,两个参数的Type Arguments用于表示dest必须包含超类型对象的对象的关系src.因此,如果你说src包含<? extends T>那么就足以说它dest包含T的对象了.

你也可以反过来表达它,即:

List<? super T> dest, List<T> src
Run Code Online (Sandbox Code Playgroud)

达到同样的效果.

编辑:我怀疑作者强调了关于PECS原则的观点


Mar*_*o13 5

正如亚特弗里克在他的回答中指出的那样,两者之间没有太大的实际区别

public static <T> void copyA(List<? super T> dest, List<? extends T> src) // and
public static <T> void copyB(List<        T> dest, List<? extends T> src)
Run Code Online (Sandbox Code Playgroud)

下面的代码段包含一个exampleShowingThatTheyAreBasicallyEquivalent.

作者选择使用的原因? super T很可能是他们想要强调PECS原则:生产者extends- 消费者super.

在此示例中,第一个列表是对象的使用者.它只接收来自其他列表的对象.因此,它的类型应该是List<? super T>.

但是,下面的代码片段还包含一个exampleShowingOneSubtleDifference.我几乎不会想到这实际上是真正相关的情况,只是指出它:当你绕过类型推断,并将类型固定<T>到一个特定类型时,你仍然可以通过在a中List<? super T>作为第一个方法的第一个参数.在第二个中,类型必须完全匹配 - 但这只是方法签名所说的,所以也许它很明显......

import java.util.List;

public class PecsExample
{
    public static void exampleShowingOneSubtleDifference()
    {
        List<? super Number> superNumbers = null;
        List<Number> numbers = null;

        PecsExample.<Number>copyA(superNumbers, numbers); // Works
        //PecsExample.<Number>copyB(superNumbers, numbers); // Does not work
    }

    public static void exampleShowingThatTheyAreBasicallyEquivalent()
    {
        List<? super Object> superObjects = null;
        List<? super Number> superNumbers = null;
        List<? super Integer> superIntegers = null;

        List<Object> objects = null;
        List<Number> numbers = null;
        List<Integer> integers = null;

        List<? extends Object> extendsObjects = null;
        List<? extends Number> extendsNumbers = null;
        List<? extends Integer> extendsIntegers = null;

        copyA(objects, objects);
        copyA(objects, numbers);
        copyA(objects, integers);
        copyA(numbers, numbers);
        copyA(numbers, integers);
        copyA(integers, integers);

        copyA(superObjects, objects);
        copyA(superObjects, numbers);
        copyA(superObjects, integers);
        copyA(superNumbers, numbers);
        copyA(superNumbers, integers);
        copyA(superIntegers, integers);

        copyA(objects, extendsObjects);
        copyA(objects, extendsNumbers);
        copyA(objects, extendsIntegers);
        copyA(numbers, extendsNumbers);
        copyA(numbers, extendsIntegers);
        copyA(integers, extendsIntegers);

        copyB(objects, objects);
        copyB(objects, numbers);
        copyB(objects, integers);
        copyB(numbers, numbers);
        copyB(numbers, integers);
        copyB(integers, integers);

        copyB(superObjects, objects);
        copyB(superObjects, numbers);
        copyB(superObjects, integers);
        copyB(superNumbers, numbers);
        copyB(superNumbers, integers);
        copyB(superIntegers, integers);

        copyB(objects, extendsObjects);
        copyB(objects, extendsNumbers);
        copyB(objects, extendsIntegers);
        copyB(numbers, extendsNumbers);
        copyB(numbers, extendsIntegers);
        copyB(integers, extendsIntegers);
    }

    public static <T> void copyA(List<? super T> dest, List<? extends T> src)
    {
        for (int i = 0; i < src.size(); i++)
        {
            dest.set(i, src.get(i));
        }
    }

    public static <T> void copyB(List<T> dest, List<? extends T> src)
    {
        for (int i = 0; i < src.size(); i++)
        {
            dest.set(i, src.get(i));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)