我不明白为什么如果没有指定类型,Java Generics会发生以下情况。假设我们有一个简单的类:
public class NumberList<T extends Number> extends ArrayList<T> {
}
然后,这很好用:
NumberList<Number> list = new NumberList<Number>();
list.add(5d);
list.add(2f);
for (Number n: list) {
System.out.println(n);
}
但是,如果我没有指定类型,则不会。
NumberList list = new NumberList();
list.add(5d);
list.add(2f);
for (Number n: list) { // Error: Change type of n to Object
System.out.println(n);
}
为什么列表迭代器现在返回对象?它不应该以某种方式默认为“最低”类(数字)?如果没有指定任何内容,我可以强制它这样做吗?
答案 0 :(得分:3)
NumberList
是原始类型。不应使用原始类型,并且仅允许与将泛型引入该语言之前编写的代码兼容。
原始类型通过替换方法参数中的所有类型并通过擦除返回类型来工作。如果T extends Number
,则T
的删除为Number
,但至关重要的是,<>
中的所有类型信息都会被删除过程忽略。在这种情况下,list
的行为就好像iterator()
返回普通的Iterator
而不是Iterator<T>
(请记住,增强的for
循环实际上只是使用语法糖Iterator
)。
有趣的是,以下编译:
NumberList list = new NumberList();
list.add(5);
Number a = m.get(0);
这是因为get
返回T
,而T
的删除是Number
。您可能希望,如果将T
视为Number
,那么Iterator<T>
应该被视为Iterator<Number>
,但由于我们只是建议不要使用原始类型,使规则尽可能简单有意义(即使它们有点奇怪)。
关于此主题的标准问题是this。
答案 1 :(得分:1)
NumberList
是原始类型,原始类型具有传染性。如果您引用原始类型,那么其所有方法也适用于原始类型。
特别是,这意味着for循环依赖的Iterator<T> iterator()
方法(基于NumberList是Iterable)变为Iterator iterator()
- 它返回一个原始Iterator类型。 Iterable的擦除是Object,而不是Number。
换句话说,从for
的角度思考这是如何看待的。使用泛型:
Iterable<Number> implicitIterable = list;
for (Number n: implicitIterable) ...
使用原始类型:
Iterable implicitIterable = list;
for (Number n: implicitIterable) ... // error! implicitIterable.next()
// returns Object, not Number