我曾认为强制转换为无界通配符类型永远不会产生“未经检查的强制转换”警告,因为无界通配符类型已被具体化,因此安全完成强制转换所需的类型信息将在运行时出现,即“强制转换为泛型类”任何(未知)类型的实例。”
此方法在指示的行产生未经检查的强制转换警告:
private static DateSerial.Metadata<?> metadataForName ( String className ) {
Class<? extends DateSerial> cls;
try {
cls = Class.forName(className).asSubclass(DateSerial.class);
} catch (ClassNotFoundException ex) {
return null;
}
--> DateSerial.Metadata<?> result = (DateSerial.Metadata<?>) Kernel
.obtainMetadata(cls)
.orElse(null);
return result;
}
该方法obtainMetadata()
返回一个Optional<T>
where<T>
是有界类型的参数<T extends DateSerial<T>>
。正如您可以从上面的代码中推断出的,提供的类型参数<T>
是? extends DateSerial
. 该方法的片段obtainMetadata
如下所示:
static <D extends DateSerial<D>> Optional<DateSerial.Metadata<D>>
obtainMetadata ( Class<D> cls ) {
Optional<Method> exe = Arrays
.stream(cls.getDeclaredMethods())
:
:
.findAny();
DateSerial.Metadata<?> k; // returned object must have type Metadata.class
try {
k = (DateSerial.Metadata<?>) exe // checked cast
.get().invoke(null);
}
catch (... ex) { return Optional.empty(); }
if (k == null || (k.getImplClass() != cls)) return Optional.empty();
@SuppressWarnings("unchecked")
DateSerial.Metadata<D> result = (DateSerial.Metadata<D>) k;
return Optional.of(result);
}
此方法反射性地查找元数据对象访问器方法并调用它。调用的方法必须具有 Metadata.class 的返回类型。请注意,局部变量k
是通过强制转换分配给无界通配符类型的。此行不生成警告。
在这个方法结束时,我已经证明元数据对象与提供的Class<D>
参数具有相同的类型,因此我可以安全地转换为返回类型(警告被抑制,因为我已经证明它是安全的)。如果<D>
是? extends DateSerial
,我希望返回类型是,Optional<Metadata<? extends DateSerial>>
但它不是。由于我不清楚的原因,带有上述类型参数的返回类型是原始类型Optional
。
两个问题:
- 为什么强制转换为无界通配符类型会在 in
metadataForName()
而不是 in生成警告obtainMetadata()
? - 当 type 参数为时
obtainMetadata()
,? extends DateSerial
为什么该方法返回原始类型Optional
?