为什么泛型参数上的通配符需要显式转换?

时间:2016-11-15 08:38:43

标签: java

我有一个功能:

<T> T get(Class<T> fetchType) {
    ...
}

所以,如果我要这样做:

String x = get(String.class);

这一切都很好。

然而,在另一个功能中:

<R> R otherFunction(R base) {
    return get(base.getClass());
}

给我一​​个错误,因为base.getClass()会返回? extends R

reason: no instance(s) of type variable(s) exist so that capture of ? extends Object conforms to R
inference variable T has incompatible bounds:
equality constraints: capture of ? extends Object upper bounds: Object, R

根据我的理解,函数get(Class<T> x)会返回T,所以当使用? extends R调用时,可以说是CAP#1,但是get现在返回CAP#1,将其分配给类型R应该不是问题。为了测试这个,我尝试了:

Class<? extends CharSequence> stringClass = String.class;
CharSequence x = get(stringClass);

这似乎没有任何问题。出了什么问题?

编辑:这是因为类型擦除,在运行时没有关于R的信息可用,但CharSequence是?哪个仍然没有意义,因为仅仅在编译阶段这不是纯粹的检查?

所以,事实证明Object.getClass()返回Class<? extends |X|>而不是Class<? extends X>,其中|X|X的删除,这就是为什么它适用于混凝土类型(如? extends CharSequence,但不适用于泛型类型)。 IntelliJ可能没有准确报告,这引起了混淆:http://i.imgur.com/yE8LswM.jpg(我尝试截取屏幕截图,但弹出窗口一直在消失)。

2 个答案:

答案 0 :(得分:6)

原因在Object.getClass的Javadoc中描述:

public final Class<?> getClass()
     

实际结果类型为Class<? extends |X|>,其中|X|是要调用getClass的表达式的静态类型的擦除。

因此,当您致电base.getClass()时,实际结果为Class<?>,因为R的删除为Object。它不是Class<? extends R>

答案 1 :(得分:0)

您的参数R base将允许所需通用类的所有对象&lt; R&gt;,但也是所有对象,它们是&lt; R>可以投入这种方法。因此,你不知道如果你调用base.getClass()会发生什么,你期望&lt; R>但它也可能是一个扩展通用R的类。