花式仿制药捕捉碰撞

请给我一个关于这里发生了什么的提示:

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 您可以实际List

 List a = new ArrayList(); List b = new ArrayList(); a.addAll(b); //ouch, would add Doubles to an Integer list 

编译器无法从List List实际类型参数是什么,因此不允许您执行添加操作。

如果将列表作为参数获取,也不应将列表转换为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 a = new ArrayList(); List b = new ArrayList(); 

也可以理解为:

 List a = new ArrayList(); List b = new ArrayList(); 

编译器应该如何知道x和y是否相同?