作者热门文章
- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我相信泛型中的类型 ?
是特定的未知类型。这意味着,声明该类型的列表将阻止我们向其中添加任何类型的对象。
List<?> unknownList;
unknownList.add(new Object()); // This is an error.
编译器按预期给出错误。
但是当未知类型是二级泛型时,编译器似乎并不关心。
class First<T> {}
List<First<?>> firstUnknownList;
// All these three work fine for some reason.
firstUnknownList.add(new First<>());
firstUnknownList.add(new First<Integer>());
firstUnknownList.add(new First<String>());
我以为编译器可能根本不关心第二层的泛型参数,但事实并非如此,
List<First<Integer>> firstIntegerList;
firstIntegerList.add(new First<String>()); // This gives a compiler error as expected.
那么,为什么编译器允许我们添加任何类型的元素,而在第二个示例中只有一个未知元素(因此没有任何元素)是可接受的?
注意:编译器 Java 1.8
最佳答案
您可以向 List<T>
添加任何内容您可以将其存储在 T
类型的引用中:
T item = ...
List<T> list = new ArrayList<>();
list.add(item);
First<?>
是 First<T>
的父类(super class)型;所以你可以存储对 First<T>
的引用在 First<?>
类型的变量中:
First<?> first = new First<String>();
因此,用 T
代替对于 First<?>
以上:
First<?> item = new First<String>();
List<First<?>> list = new ArrayList<>();
list.add(item);
OP 示例中发生的所有事情是临时变量 item
被省略:
firstUnknownList.add(new First<String>());
但是,如果您使用 firstIntegerList
执行此操作示例:
First<Integer> item = new First<String>(); // Compiler error.
List<First<Integer>> list = new ArrayList<>();
list.add(item);
很明显为什么不允许这样做:您不能分配 item
.
还可以看出,您不能对该列表的内容做任何不安全的事情。
如果您向接口(interface)添加几个方法:
interface First<T> {
T producer();
void consumer(T in);
}
现在,考虑一下您可以对添加到列表中的元素做什么:
for (First<?> first : firstUnknownList) {
// OK at compile time; OK at runtime unless the method throws an exception.
Object obj = first.producer();
// OK at compile time; may fail at runtime if null is not an acceptable parameter.
first.consumer(null);
// Compiler error - you can't have a reference to a ?.
first.consumer(/* some maybe non-null value */);
}
因此实际上您无法对该列表中的元素做任何违反类型安全的事情(前提是您不做任何故意违反它的事情,例如使用原始类型)。您可以证明通用生产者/消费者方法同样安全或被编译器禁止。
所以没有理由不允许您这样做。
关于java - (?) 通配符泛型的不规则性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39014559/
我是一名优秀的程序员,十分优秀!