关于java:Generics Upper Bound Wild Card会出现编译错误

Generics Upper Bound Wild Card gives compilation error

本问题已经有最佳答案,请猛点这里访问。

我尝试了一些关于泛型上界/下界的示例程序。泛型上界给出了编译错误…但下界可以。我只是想把t类型的列表放入一个集合中,并尝试使用上界和下界方案。

请帮助识别testUpperbound(t)方法的问题,以及为什么testLowerbound(t)方法编译而testUpperbound(t)方法不编译。我检查了其他类似的线程。但我仍然没有弄清楚。

如果需要更多细节,请告诉我。

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
 public class TestGenerics<T>
    {

        public static void main(String...args)
        {
           List<String> list = new ArrayList<>();
           list.add("New ArrayList");
           new TestGenerics<List<String>>().testUpperBound(list);
           new TestGenerics<List<String>>().testLowerBound(list);

        }

       public  void testLowerBound(T t)
       {
            Set<? super ArrayList<T>> lowerBoundSet = new HashSet<>();
            lowerBoundSet = new HashSet<List<T>>();
            ArrayList<T> list = new ArrayList<>();
            list.add(t);
            lowerBoundSet.add(list);  // compiles..

            out.println(lowerBoundSet);
        }

        public  void testUpperBound(T t)
        {
            Set<? extends List<T>> upperBoundSet = new HashSet<>();
            upperBoundSet = new HashSet<List<T>>();
            ArrayList<T> list = new ArrayList<>();
            list.add(t);
            upperBoundSet.add(list);  // Doesn't compile..

            out.println(upperBoundSet);
        }

    }

简而言之,我们在编译时不知道upperBoundSet中包含什么类型的列表。它可以是一个Set>,也可以是一个Set>,或者它可以是许多其他选择之一。

如果结果是一个Set>,那么在它上面加一个ArrayList显然是一个坏主意。但是因为我们不知道集合的内容是什么类型,所以它采用了更安全的选项并阻止了它。


下面是您的答案:

GET-PUT原理的解释

它是Java规则,仅此而已。我可以给您举一个例子,说明如果编译通过,它将不安全的原因:

1
2
3
4
5
6
7
8
9
10
11
public void extendsExample(){
  Set<? extends List<? extends String>> setOfList = new HashSet<>();
  Set<ArrayList<String>> setOfArrayList = new HashSet<>();

  // now setOfList var refers to a set
  // which contains a arraylist of String
  setOfList = setOfArrayList;

  // compilation fails
  setOfList.add(new LinkedList<String>());
 }

假设编译没有失败。它是指setOfArrayList实例,它是一个集合,应该包含ArrayList实例,现在包含LinkedList元素的列表。

如果您迭代setOfArrayList元素,您将不会像预期的那样独占ArrayList元素。这是不安全的,这就是编译失败的原因。

这里是的示例:

1
2
3
4
5
6
7
8
9
10
11
public void superExample(){
  Set<? super ArrayList<String>> setOfArrayList = new HashSet<>();

  // compilation ok
  setOfArrayList.add(new ArrayList<String>());
  // new anonymous type derivating from ArrayList
  ArrayList<String> derivedArrayList = new ArrayList<String>(){
  };
  // compilation ok
  setOfArrayList.add(derivedArrayList);
}


不能修改用参数化的集合。Java只是不允许,因为它是不安全的动作。add()修改集合,因此无法执行该操作。对没有这样的限制。