java - 为什么设置>允许,但设置> 不是
问题描述
我想知道泛型在这种情况下是如何工作的,为什么
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> {}
解决方案
简单地说,这是因为Set<? extends Foo<?>>
是协变的(与extends
关键字)。协变类型是只读的,编译器将拒绝任何写操作,例如Set.add(..)
.
Set<Foo<?>>
不是协变的。它不会阻止写入或读取操作。
这个...
Set<Foo<String>> set1 = new HashSet<>();
Set<Foo<?>> set2 = set1; // KO by compiler
... 是非法的,因为否则我可以将 aFoo<Integer>
放入set1
via 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
请参阅这些帖子以获得更好的解释:
推荐阅读
- wpf - 展台模式 WPF 应用程序抛出 Windows 配置设计器
- react-day-picker - 反应日期选择器覆盖始终打开
- angular6 - ./node_modules/ng2-completer/esm5/ng2-completer.js 找不到模块:错误
- visual-studio - 在 Visual Studio 中为 REST Api 负载测试选择哪个测试组合模型选项?
- python - gcloud 部署管理器模板中的 python 模块
- java - 哪个方程代表二次时间
- matlab - 在 App Designer 图窗中显示视频流
- c# - 无法从程序集 ']0987654RE3W23SD 加载类型 'Invalid_Token.0x02000000',版本 = 1.0.0.0,文化 = 中性,PublicKeyToken = null'
- sql - 不使用循环计算行程次数
- json - 在 Go 中将 Json 数据解组到地图中