4

该程序无法编译:

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()returnClass<? extends Object>而不是Class<? extends T>

4

3 回答 3

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()考虑一下: is的返回类型,Class<?>编译器将希望将其捕获?为具体类型。但是相反,我们不想捕获?,而是“捕获上限” T——Java 的泛型中没有这样的东西。

于 2012-05-24T19:56:14.103 回答
1

Object.getClass()定义为返回 a Class<? extends |T|>,其中T是接收者的静态已知类型(对象getClass()被调用)。特别注意竖线,擦除操作符。类型变量的擦除是其最左边界的擦除。在你的情况下,这是隐含的 bound 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!

但幸运的是,我们确实收到了警告.. ;)

于 2012-05-24T21:32:50.883 回答
0

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

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

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

于 2012-05-24T21:21:10.977 回答