Java泛型不兼容类型编译错误,用于Oracle Java SE 8u20 JDK中的通用静态方法调用

时间:2014-09-28 19:29:31

标签: java generics compilation type-erasure incompatibletypeerror

使用Oracle Java SE 8u20 JDK编译下面的代码时,前三个赋值编译正常(对于works*变量),但第四个赋值(对于fails1变量)生成以下内容编译错误:

错误:

incompatible types: Set<Set<Object>> cannot be converted to Set<Set<? extends Object>>

代码:

import java.util.Set;
import java.util.Collections;

...

Set<? extends Object>      works1 = Collections.<Object>emptySet();
Set<Set<Object>>           works2 = Collections.<Set<Object>>emptySet();
Set<Set<? extends Object>> works3 = Collections.<Set<? extends Object>>emptySet();
Set<Set<? extends Object>> fails1 = Collections.<Set<Object>>emptySet();

我认为这是正确的(可能是由于Java语言规范中定义的某种类型的擦除),而不是一个bug,但我不确定。

有谁知道为什么fails1无法编译?可以理解对Java规范的适用部分或JDK错误报告的引用。

感谢您的帮助。

2 个答案:

答案 0 :(得分:3)

<&amp;之间的任何内容>是类型不变的,除非您使用?通配符。

Set<? extends Object>&amp;的类型Set<Object>不同,因此需要将类型差异视为兼容。

如果他们处于最高级别,就像works1一样,顶级Set位于<&amp; >,因此正常的Java类型差异有效,但对于fails1,它们位于<&amp; >,因此类型是不变的。

可以在<&amp; >通过从Set<Set<...>> Set<? extends Set<...>>更改类型声明的最外层部分。{/ p>

因此,以下代码正确编译:

Set<? extends Set<? extends Object>> works4 = Collections.<Set<Object>>emptySet();

我从以下问题的回答中得出了答案(上面提到了@MarkoTopolnik):

multiple nested wildcard - arguments not applicable

以下问题的答案提供了更详细的解释:

Can't cast to to unspecific nested type with generics

答案 1 :(得分:2)

您在fails1上的输入过于严格,这与声明时对其施加的相对宽松的通配符约束相矛盾。

? extends T形式的upper-bounded wildcard表示您愿意接受T及其所有子类型。但是,您明确将右侧限制为Object

从本质上讲,你试图采取:

Set<Set<? extends Object>>

这是一组包含Object或扩展Object ...

的集合

...并把它变成这个:

Set<Object>

一组Object类型。

这就是为什么works1不会发生这种情况的原因:它定义了一个Set,其中包含ObjectObject的后代的元素。 Object,由于{{1}}至少满足其中一项要求,因此在后台完成的capture conversion将符合此规则。

然后再次,这是你正在使用的Java 8 - 除非Java编译器不能在这里进行类型推断,否则你传递这些类型几乎没什么好处。