使用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错误报告的引用。
感谢您的帮助。
答案 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
以下问题的答案提供了更详细的解释:
答案 1 :(得分:2)
您在fails1
上的输入过于严格,这与声明时对其施加的相对宽松的通配符约束相矛盾。
? extends T
形式的upper-bounded wildcard表示您愿意接受T
及其所有子类型。但是,您明确将右侧限制为Object
。
从本质上讲,你试图采取:
Set<Set<? extends Object>>
这是一组包含Object
或扩展Object
...
...并把它变成这个:
Set<Object>
仅一组Object
类型。
这就是为什么works1
不会发生这种情况的原因:它定义了一个Set
,其中包含Object
或Object
的后代的元素。 Object
,由于{{1}}至少满足其中一项要求,因此在后台完成的capture conversion将符合此规则。
然后再次,这是你正在使用的Java 8 - 除非Java编译器不能在这里进行类型推断,否则你传递这些类型几乎没什么好处。