Java泛型编译错误涉及类<! - ?延伸T - >

时间:2012-05-24 19:46:30

标签: java generics

此程序无法编译:

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>

3 个答案:

答案 0 :(得分: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的泛型中没有这样的东西。

答案 1 :(得分:1)

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

为什么?

想象一下T = List<Integer>,您可以突然执行以下未经检查的警告

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!

但幸运的是我们收到警告..;)

答案 2 :(得分:0)

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

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

通常,对泛型类使用反射的API要求客户端将类型为Class< T >的附加参数传递给相关的构造函数或泛型方法。