Java 如何处理泛型的不明确类型推断?



在此代码中,T 可以是 A、B、C 或 D,但 Eclipse 显示它是 D。

static class A { }
static class B extends A { }
static class C extends B { }
static class D extends C { }
static <T> void copy(List<? super T> dst, List<? extends T> src) {
for (T t : src)
dst.add(t);
}
public static void main(String[] args) {
List<A> dst = new ArrayList<>();
List<D> src = new ArrayList<>();
copy(dst, src); // Eclipse shows T is D
}

对于如何进行类型推断以及为什么选择 D 是否有任何规则?

对于如何进行类型推断,是否有任何规则

是的,Java 语言规范的整个第 18 章都专门讨论这个主题:-)

为什么选择 D?

我认为以下规则对此负责:

如果绑定集不包含形式为 G<..., αi, ...> = 捕获(G<...>) 对于所有 i (1 ≤ i ≤ n),则为每个 αi 定义候选实例化 Ti:

  • 如果 αi 有一个或多个适当的下限 L1, ..., Lk,则 Ti = lub(L1, ..., Lk) (§4.10.4)。

  • 否则,如果绑定集包含抛出 αi,并且 αi 的正确上限最多是 Exception、Throwable 和 Object,则 Ti = RuntimeException。

  • 否则,其中 αi 具有适当的上限 U1, ..., Uk, Ti = glb(U1, ..., Uk) (§5.1.10)。

边界 α1 = T1, ..., αn = Tn 与当前边界集合并。

如果结果不包含绑定 false,则结果将成为新的绑定集,并且通过选择一组新的变量进行实例化(如有必要)进行解析,如上所述。

简单来说,当尝试类型参数的可能值时,编译器首先尝试下限,如果合适,则使用该下限。

在我们的例子中,约束集说D extends T and D extends A,所以T的下限是D,所以D是第一个候选替换。

编译器通过假设T = D来验证D是否合适,这将约束集简化为D extends D and D extends A,两者都已知为真。

因此,编译器使用D.

最新更新