2012-01-06 36 views
2

以下代码有注释,表示两条相似的行,其中一条编译,其中一条不行。是通过设计还是忽略了Java的常量特定类体的非泛型getClass()方法?

public class TestGenericCollections extends TestCase { 
    List<Key<? extends Enum<?>>> keyList; 

    public TestGenericCollections() { 
    keyList = Lists.newArrayList(); 
    } 

    public <T extends Enum<T>> void addEnum(List<T> values) { 
    Preconditions.checkArgument(values.size() > 0); 
    // Signature of Key.get(): 
    // public static <T> Key<T> get(Class<T> type) 

    // the following line compiles without warning or error 
    keyList.add(Key.get(values.get(0).getDeclaringClass())); 
    // The following line fails to compile with this error message in Eclipse: 
    // The method add(Key<? extends Enum<?>>) in the type List<Key<? extends Enum<?>>> 
    // is not applicable for the arguments (Key<capture#1-of ? extends Enum>) 
    keyList.add(Key.get(values.get(0).getClass())); 
    } 

错误信息非常有趣。请注意,没有Enum<?>,这是生的Enum。这意味着任何泛型方法/集合/等。如果想要避免编译器警告,那么想要在匿名常量类体上操作的枚举类型必须放弃泛型并使用注释@SuppressWarnings(“rawtypes”)。这就是为什么这行不会编译,但它会超过它。 Enum<T>.GetDeclaringClass()正确地返回一个泛型类型,但编译器创建的每个Enum值不变的匿名常量特定类不会。

那么,基本原理是什么?这是一种疏忽吗?或者说是语言设计者没有改变EnumEnumgetClass()方法的匿名常量特定类体上的签名是否类似于他们在将Java泛型添加到语言时所做的那样?

+0

什么类是'Key'? – Bohemian 2012-01-06 06:41:55

+0

这是Guice的一部分,但这对于这个目的无关紧要。您可以将集合类型想象为List >>,你会得到相同的结果。 – 2012-01-06 06:52:08

回答

1

什么你的建议是有用的。但我不会把它称之为疏忽。

getClass()的签名在语言规范中有特别的定义,并且需要特殊的编译器处理。

为了得到你想要的,语言规范需要枚举的另一个例外。附加规则并不简单。用例可能不足以证明成本。

-

如果getClass()回报Class<? extends X>而不是Class<? extends |X|>,这将是在大多数情况下,使用了很多更加有用(如在你的例子)。这在理论上是不正确的,但实际上它在直观使用中是安全的。我们可以自己定义这样一个getClass()

@SuppressWarnings("unchecked") 
static public <T> Class<? extends T> getClass(T obj) 
{ 
    return (Class<? extends T>)obj.getClass(); 
} 


// compiles 
keyList.add(Key.get(getClass(values.get(0)))); 
+0

谢谢,这解释了它,我看到这种行为不是特定于枚举,任何泛型类型都有这种行为。我想当我在javadoc中看到getClass()的签名时,它返回了一个类,我假设它直观地操作并且没有深入其中。擦除再次咬伤。 – 2012-01-06 16:59:55

1

Object.getClass()的静态返回类型是Class<? extends |X|>其中X是对象的静态类型。 ? extends,因为对象的实际类型可能是其静态类型的子类型,并且由于每个泛型声明只有一个类对象,所以将其擦除|X|。这两个限制都不适用于(1)final和(2)从不通用的枚举。因此getDeclaringClass()的静态返回类型为Class<X>是合理的。 getClass()未被覆盖任何地方任何类,因为它是final

(我认为这个回答你的问题。)

相关问题