首页 > 解决方案 > 为什么设置>允许,但设置> 不是

问题描述

我想知道泛型在这种情况下是如何工作的,为什么 Set<? extends Foo<?>> set3 = set1;允许但Set<Foo<?>> set2 = set1;不允许?

import java.util.HashSet;
import java.util.Set;

public class TestGenerics {
    public static <T> void test() {
        Set<T> set1 = new HashSet<>();
        Set<?> set2 = set1;             // OK
    }

    public static <T> void test2() {
        Set<Foo<T>> set1 = new HashSet<>();
        Set<Foo<?>> set2 = set1;           // COMPILATION ERROR
        Set<? extends Foo<?>> set3 = set1; // OK
    }
}

class Foo<T> {}

标签: javagenerics

解决方案


简单地说,这是因为Set<? extends Foo<?>>是协变的(与extends关键字)。协变类型是只读的,编译器将拒绝任何写操作,例如Set.add(..).

Set<Foo<?>>不是协变的。它不会阻止写入或读取操作。

这个...

Set<Foo<String>> set1 = new HashSet<>();
Set<Foo<?>> set2 = set1; // KO by compiler

... 是非法的,因为否则我可以将 aFoo<Integer>放入set1via set2

set2.add(new Foo<Integer>()); // Whoopsie

但...

Set<Foo<String>> set1 = new HashSet<>();
Set<? extends Foo<?>> set3 = set1; // OK

... 是协变的(extends关键字),所以它是合法的。例如,编译器将拒绝类似的写操作set3.add(new Foo<Integer>()),但接受类似的读操作set3.iterator()

Iterator<Foo<String>> fooIterator = set3.iterator(); // OK
set3.add(new Foo<String>()); // KO by compiler

请参阅这些帖子以获得更好的解释:


推荐阅读