【发布时间】:2020-10-16 15:23:34
【问题描述】:
我不知道如何简明扼要地表达这个问题的标题。我发现了一些相关的问题,例如this one,但似乎没有一个明确回答我的问题。
但基本上我要问的是:
考虑下面的代码
static <A, B> Class<? extends A> getLeftClass(Pair<A, B> tuple) {
A left = tuple.getLeft();
return left.getClass();
}
按原样,此代码无法编译。编译失败并出现错误
Type mismatch: cannot convert from Class<capture#20-of ? extends Object> to Class<? extends A>
我认为这本质上是因为getClass 返回一个类型Class<? extends Object>,但编译器期待Class<? extends A>。
一种解决方案是按如下方式转换类:
static <A, B> Class<? extends A> getLeftClass(Pair<A, B> tuple) {
A left = tuple.getLeft();
return (Class<? extends A>) left.getClass();
}
这样编译。但是,由于未经检查的强制转换而出现警告。
我的问题是,警告是否合理?有正当理由不这样做吗?或者这只是编译器无法验证它是否正确的情况,但只要tuple.getLeft() 确实是A 的实例,它就会一直工作?
顺便说一下,Pair 类是 this one,来自 Apache 公共库
【问题讨论】:
-
你的假设对我来说是正确的。我认为
x.getClass()没有将其返回类型声明为Class<? extends X>是 Java 泛型的一个怪癖;特别是因为编译器有时会像对待它一样对待它。 -
尝试使用返回类型为
Class<A>的原始代码。我认为extends是错误的。如果有的话,类类型应该是 A 的超类,而不是子类。 -
@markspace
A类型的变量可以在运行时保存A类型或A的任何子类型的对象。因此Class<? extends A>. -
@khelwood 我不认为泛型是这样协变的。
A不是变量而是类型参数。它的类型只能是 A。(至少,在没有任何限制的情况下,我认为A不会解析为除自身之外的任何内容。)
标签: java generics casting type-erasure