Oracle Java SE 8u20中的泛型静态方法调用的Java泛型不兼容类型编译错误Java SE 8u20 JDK
使用Oracle Java SE 8u20 JDK编译以下代码时,前三个赋值可以正常编译(对于works*
变量),但第四个赋值(用于fails1
变量)生成以下编译错误:Oracle Java SE 8u20中的泛型静态方法调用的Java泛型不兼容类型编译错误Java SE 8u20 JDK
错误:
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语言规范中定义的某种类型的擦除),而不是一个错误,但我不确定。
有谁知道为什么fails1
无法编译?对Java规范的适用部分或JDK错误报告的引用将不胜感激。
感谢您的任何帮助。
任何除非你使用?
通配符类型不变。
Set<? extends Object>
& 的类型不同,因此需要将类型差异视为兼容。
如果他们是在顶层,作为works1
,顶级Set
是<
& >
外面,所以普通的Java类型变化的工作,但对于fails1
,他们是<
& >
内,所以类型是不变的。
类型方差内<
& >
通过从Set<Set<...>>
Set<? extends Set<...>>
改变类型声明的最外部分被启用。
因此,下面的代码编译正确:
Set<? extends Set<? extends Object>> works4 = Collections.<Set<Object>>emptySet();
我衍生我的答案从回答以下问题(这是由@MarkoTopolnik如上所述):
multiple nested wildcard - arguments not applicable
的回答以下问题提供了更详细的解释:
您在fails1
上输入的内容过于狭窄,这与在声明时强加给它的相对较松散的通配符限制相矛盾。
形式为? extends T
的upper-bounded wildcard意味着您愿意接受T
及其所有子类型。但是,您明确限制右侧为Object
。
从本质上说,你要采取:
Set<Set<? extends Object>>
这是一组包含的东西是一个Object
或扩展Object
套...
......并把它成这样:
Set<Object>
其是仅一套Object
类型。
还有一个原因,这种情况不符合works1
发生:它定义了一个Set
其中包含的一些元素是Object
或Object
后裔,自Object
满足这些要求的至少一个,该capture conversion之中在后台完成将履行这一规则。
然后,这就是您正在使用的Java 8 - 除非Java的编译器无法在此处进行类型推断,否则在您传递这些类型时根本没有什么收获。 <
& >
之间
我认为最重要的信息应该是顶层'?'和嵌套位置'''之间的区别。也就是说,为什么你的解释不适用于'works1'。在表面上看,这里的限制性右边也是如此。不同之处在于顶级'?'受到通配符捕获,而嵌套的不是。 – 2014-09-28 19:51:18
这不是一个坏主意。我将在大约半小时内完成这项工作。试图用一种令人满意的方式来理解它。 – Makoto 2014-09-28 19:54:50
它也不能在Java 7上编译。 – Makoto 2014-09-28 19:33:56
请记住,类型擦除不会是编译错误(如当前错误)的答案。在编译时没有擦除---所有类型的信息都在那里。 – 2014-09-28 19:46:53
我推荐阅读这个问答:http://stackoverflow.com/questions/3652718/multiple-nested-wildcard-arguments-not-applicable – 2014-09-28 19:59:49