Collections.emptyList()和/或Java通用方法的奇怪类型推断行为?

问题描述:

这是jdk1.7.0_04Collections.emptyList()和/或Java通用方法的奇怪类型推断行为?

我尝试使用Collections.emptyList(),而不是new荷兰国际集团我自己的空单在条件:

List<String> list = (anArray != null) ? Arrays.asList(anArray) : Collections.emptyList(); 

但出现以下错误:

error: incompatible types 
     List<String> list = (anArray != null) ? Arrays.asList(anArray) : Collections.emptyList(); 
              ^
    required: List<String> 
    found: List<CAP#1> 
    where CAP#1 is a fresh type-variable: 
    CAP#1 extends Object from capture of ? extends Object 
1 error 

我能身影,我需要改变的东西:

List<String> list = (anArray != null) ? Arrays.asList(anArray) : Collections.<String>emptyList(); 

但作为工作的一部分关于这一点,我遇到了奇怪的(对我来说,反正)局面:

List<String> alwaysEmpty = Collections.emptyList(); 

编译罚款,但:

List<String> alwaysEmpty = (List<String>) Collections.emptyList(); 

提供了以下编译错误:

error: inconvertible types 
     List<String> alwaysEmpty = (List<String>) Collections.emptyList(); 
                    ^
    required: List<String> 
    found: List<Object> 

什么鬼??现在

我可以理解,也许一些奇怪的原因使用条件运算符是从某种程度上意识到了emptyList()呼叫类型参数应该是String阻塞型推理系统,所以它需要被明确指定。但为什么插入一个(承认冗余)演员搞砸了?

But why does inserting a (admittedly redundant) cast mess things up?

因为现在本身表达Collections.emptyList()没有任何赋值的目标 - 所以应该选择什么类型的参数?这只是为了更好地指定类型参数:

// Redundant here, but just as an example 
List<String> alwaysEmpty = Collections.<String>emptyList(); 

它适用于有条件的经营者一样,太:

public static void main(String[] args) {    
    List<String> list = (args != null) 
     ? Arrays.asList(args) : Collections.<String>emptyList(); 
} 

我要去接受乔恩的答案,但也希望列为答案这个外面有人传给我的是什么。这是提交给Sun/Oracle的关于这件事的bug report的链接。评估错误的人对发生的事情有一个有用的解释。摘录:

The submitter here seems to assume that the type of a conditional expression is the type on the LHS of an assigment (List<String> in this case). This is not true: as stated by the JLS, the type of a conditional expression:

"The type of the conditional expression is the result of applying capture conversion (§5.1.10) to lub(T1, T2) (§15.12.2.7). "

It's important to understand why it's necessary to apply lub. Consider the following example:

class A {} 
class B extends A{} 
class C extends A{} 
class Foo<X> 
Foo<? extends A> l = b ? new Foo<B>() : new Foo<C>() 

In this case we have that LHS is of type Foo<? extends A> while the RHS is of type lub(Foo<B>, Foo<C>) , that is Foo<? extends B&C> .