关于java:copy(List dest, List src) ` 和`copy(List dest, List src)`之间的差异`

Differences between `copy(List<? super T> dest, List<? extends T> src) ` and `copy(List<T> dest, List<? extends T> src)`

我试图通过阅读以下内容来学习Java泛型通配符:http://www.angelikalanger.com/genericsfaq/faqsections/typearguments.html faq103

材料中有一个示例:

1
2
3
4
5
6
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));
  }
}

我想知道是否可以将方法签名更改为以下内容:

1
  public static <T> void copy(List<? super T> dest, List<? extends T> src) {

γ

1
  public static <T> void copy(List<T> dest, List<? extends T> src) {

这两种方法有什么不同吗?

我们将不胜感激。


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

1
2
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)

下面的代码段包含一个exampleShowingThatTheyAreBasicallyEquivalent

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

在本例中,第一个列表是对象的使用者。它只接收来自另一个列表的对象。因此,它的类型应该是List

然而,下面的代码片段也包含一个exampleShowingOneSubtleDifference。我很难想到这与实际相关的情况,但我只是想指出:当您绕过类型推理,将类型固定为一个特定类型时,您仍然可以将List作为第一个方法的第一个参数传递给第一个方法。在第二个例子中,类型必须完全匹配——但这只是方法签名所说的,所以可能很明显……

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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));
        }
    }
}


你是对的。在这种情况下,两个参数的类型参数被用来表示dest必须包含src中对象的超类型的对象的关系。因此,如果你说src包含,那么就足以说dest包含t的对象。

你也可以用另一种方式表达,即:

1
List<? super T> dest, List<T> src

达到同样的效果。

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