请给我一个关于这里发生了什么的提示:
List<? extends Number> a = new ArrayList<Number>();
List<? extends Number> b = new ArrayList<Number>();
a.addAll(b); // ouch! compiler yells at me, see the block below:
/*
incompatible types
found : java.util.List<capture#714 of ? extends java.lang.Number>
required: java.util.List<java.lang.Number>
*/
Run Code Online (Sandbox Code Playgroud)
这个简单的代码无法编译.我依稀记得与类型捕获有关的东西,比如应该主要用于接口规范,而不是实际的代码,但我从来没有像这样傻眼.
这当然可能是强力固定的,就像那样:
List<? extends Number> a = new ArrayList<Number>();
List<? extends Number> b = new ArrayList<Number>();
@SuppressWarnings({"unchecked"})
List<Number> aPlain = (List<Number>) a;
@SuppressWarnings({"unchecked"})
List<Number> bPlain = (List<Number>) b;
aPlain.addAll(bPlain);
Run Code Online (Sandbox Code Playgroud)
那么,我是否真的必须放弃声明中的捕获(捕获来自界面,所以我将不得不更改一些API),或坚持使用抑制注释的类型转换(这通常会使代码变得混乱和复杂化一点点)?
您基本上有两个可能不同类型的列表.因为? extends Number意味着一个延伸的类Number.因此,对于列表,a它可以是classA列表b,例如classB.它们不兼容,它们可能完全不同.
问题是,如果你使用List<? extends Number>你实际上可以做:
List<? extends Number> a = new ArrayList<Integer>();
List<? extends Number> b = new ArrayList<Double>();
a.addAll(b); //ouch, would add Doubles to an Integer list
Run Code Online (Sandbox Code Playgroud)
编译器无法判断List<? extends Number>实际类型参数是什么,因此不允许您执行添加操作.
List<Number>如果将它们作为参数获取,也不应该将列表强制转换,因为实际上可以有一个Integer对象列表并向其添加Double对象.
在这种情况下,您最好创建一个新的List<Number>并从两个列表中添加对象:
List<Number> c = new ArrayList<Number>(a.size() + b.size());
c.addAll(a);
c.addAll(b);
Run Code Online (Sandbox Code Playgroud)
编辑:如果你在本地创建两个列表,你不会得到?通配符(因为你一直有List<Number>).
不要使用?通配符。它的意思是“我不知道某些特定类型”,并且由于您不知道该类型,因此无法将任何内容添加到列表中。更改您要使用的代码List<Number>,一切都会正常。
这正迅速成为最常见的 Java 问题,有一百种变体......