我想要解决一个多年来一直影响我的代码某些部分的疑点--它是用简单的强制转换修复的,但现在我想了解它背后的基本原理,并可能在官方规范中引用它.
让我来介绍这段代码:
import java.util.function.Supplier;
class BaseClass<T, R> {
R getSomething() { return null; }
static <U> U method1 (final U arg1) { return arg1; }
static <U> U method2 (final U arg1, final Class<? extends U> arg2) { return arg1; }
static <U> U method3 (final U arg1, final Supplier<? extends U> arg2) { return arg1; }
}
现在,让我有一个带有部分泛型绑定的子类(T
仍未绑定):
class DerivedClass<T> extends BaseClass<T, String> {
private String s;
void test (final DerivedClass<T> arg) {
final var m1 = method1(arg);
s = m1.getSomething();
final DerivedClass<T> m3 = method1(arg);
s = m3.getSomething();
final var m2 = method2(arg, DerivedClass.class);
// 1. ERROR: requires String, found Object
s = m2.getSomething();
// 2. WARNING: unchecked assignment DerivedClass to DerivedClass<T>
final DerivedClass<T> m4 = method2(arg, DerivedClass.class);
s = m4.getSomething();
final var m5 = method3(arg, () -> new DerivedClass<>());
s = m5.getSomething();
}
}
对于method1
,一切都很好,返回的对象带有绑定R
->;String
.换句话说,arg1
的U
类型被正确地传播到结果.
如果使用method2
,绑定就会丢失(并"降级"到Object
):如果使用m4
的显式类型声明强制执行操作(当然,显式强制转换也可以),则会发出警告;如果使用var
,则会出现错误.
method3
,尽管有arg2
人以与method2
人相似的方式宣布,但一切又好起来了.
因此,罪魁祸首似乎是存在一个Class<>
类型的参数.为什么?一般来说,为什么即使有Class<>
个参数,编译器也不使用arg1
作为完全匹配呢?
据我所知,这种情况是从Java 5开始发生的(当然,var
的部分指的是Java 17).
谢谢.