花式仿制药捕捉碰撞
请给我一个关于这里发生了什么的提示:
List a = new ArrayList(); List b = new ArrayList(); a.addAll(b); // ouch! compiler yells at me, see the block below: /* incompatible types found : java.util.List required: java.util.List */
这个简单的代码无法编译。 我依稀记得与类型捕获有关的东西,比如应该主要用于接口规范,而不是实际的代码,但我从来没有像这样傻眼。
这当然可能是powershell固定的,就像那样:
List a = new ArrayList(); List b = new ArrayList(); @SuppressWarnings({"unchecked"}) List aPlain = (List) a; @SuppressWarnings({"unchecked"}) List bPlain = (List) b; aPlain.addAll(bPlain);
所以,我是否真的必须放弃声明中的捕获(捕获来自界面,所以我将不得不更改一些API),或坚持使用抑制注释的类型转换(这通常会使代码变得混乱和复杂化一点点)?
您基本上有两个可能不同类型的列表。 因为? extends Number
? extends Number
表示? extends Number
的类。 因此,对于列表a
它可以是classA
,对于列表b
它可以是例如classB
。 它们不兼容,它们可能完全不同。
问题是,如果你使用List extends Number>
您可以实际List extends Number>
:
List extends Number> a = new ArrayList(); List extends Number> b = new ArrayList(); a.addAll(b); //ouch, would add Doubles to an Integer list
编译器无法从List extends Number>
List extends Number>
实际类型参数是什么,因此不允许您执行添加操作。
如果将列表作为参数获取,也不应将列表转换为List
,因为实际上可以有一个Integer对象列表并向其添加Double对象。
在这种情况下,您最好创建一个新的List
并添加两个列表中的对象:
List c = new ArrayList (a.size() + b.size()); c.addAll(a); c.addAll(b);
编辑:如果你在本地创建两个列表,你不会发现?
无论如何都要使用通配符(因为你总是有List
)。
不要用?
通配符。 它表示“某些特定类型我不知道”,并且由于您不知道类型,因此无法向列表中添加任何内容。 将代码更改为使用List
,一切都会正常工作。
这很快成为最常见的Java问题,在一百种变化中…
PECS(生产者扩展,消费者超级)
- 您不能将任何内容放入使用EXTENDS通配符声明的类型中,除了属于每个引用类型的值null
- 你不能从使用SUPER通配符声明的类型中获取任何东西,除了Object类型的值,它是每个引用类型的超类型
事情是:
List extends Number> a = new ArrayList(); List extends Number> b = new ArrayList ();
也可以理解为:
List a = new ArrayList(); List b = new ArrayList();
编译器应该如何知道x和y是否相同?