2012-05-24 68 views
4

这个程序不编译:Java泛型编译错误涉及<? extends T>类

public class xx { 
    static class Class1<C> { 
     void method1(C p) { 
     } 
    } 
    static class Class2<T> extends Class1<Class<? extends T>> { 
     T object; 
     void method2() { 
      this.method1(this.object.getClass()); 
     } 
    } 
} 

的错误是:

xx.java:10: method1(java.lang.Class<? extends T>) in xx.Class1<java.lang.Class<? extends T>> 
cannot be applied to (java.lang.Class<capture#215 of ? extends java.lang.Object>) 
     this.method1(this.object.getClass()); 

为什么会出现这种情况?为什么编译器似乎认为object.getClass()回报Class<? extends Object>代替Class<? extends T>

回答

1

Object.getClass()被定义为返回Class<? extends |T|>,其中T是接收器的静态已知类型(对象getClass()被调用)。请特别注意竖条,erasure operator。擦除类型变量是删除其最左边界。在你的情况下,这是隐含的约束Object。所以你找回Class<? extends Object>,而不是Class<? extends T>

这是为什么?

想象​​,你会突然做以下没有选中警告

List<String> myStrings = new ArrayList<>(); 
List<Integer> myInts = new ArrayList<>(); 
List<Integer> myIntyStrings = myInts.getClass().cast(myStrings); 
myIntyStrings.add(-1); 
String myString = myStrings.get(0); // BANG! 

所幸我们就得到一个警告..;)

+0

谢谢,为我澄清! – Archie

4

您的代码中没有上限设置T,所以? extends T实际上相当于? extends Object。就在昨天,我玩了一个类似的例子,并击中了这个障碍。我有

static <T> T newInstance(T o) throws Exception { 
    final Class<? extends T> c = o.getClass(); 
    return c.newInstance(); 
} 

它抱怨与相同的错误。想想看:的Object.getClass()返回类型为Class<?>,编译器将要在?捕捉到一个具体类型。但是相反,我们想不捕捉?,但“占领上限” T - 并且在Java的泛型没有这样的事情。

+0

谢谢,这解释了为什么我们得到'?扩展Object“,但不是编译失败的原因。我的意思是,不应该编译器“知道”'object.getClass()'返回'类''因为有object'键入'T'? – Archie

+0

编辑回答... –

0

根据getClass()的文档,返回的对象的类型为Class< ? extends |X| >,其中|X|是擦除调用该方法的实例类型。

因此,在类型为T的对象上调用getClass()会返回Class< ? extends Object >。我们在此API中没有关于T的绑定信息。

一般的API,其上一般类使用反射要求客户端传递Class<T>类型的附加参数所讨论的构造或通用方法。