Java 如何处理泛型的模糊类型推断?
How does Java handle ambiguous type inference for generics?
这段代码中,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 是否有任何规则?
Is there any rule for how type inference is done
是的,entire 18th chapter of the Java Language Specification 专门讨论这个话题:-)
and why it selects D?
我认为以下规则对此负责:
If the bound set does not contain a bound of the form G<..., αi, ...> = capture(G<...>) for all i (1 ≤ i ≤ n), then a candidate instantiation Ti is defined for each αi:
If αi has one or more proper lower bounds, L1, ..., Lk, then Ti = lub(L1, ..., Lk) (§4.10.4).
Otherwise, if the bound set contains throws αi, and the proper upper bounds of αi are, at most, Exception, Throwable, and Object, then Ti = RuntimeException.
Otherwise, where αi has proper upper bounds U1, ..., Uk, Ti = glb(U1, ..., Uk) (§5.1.10).
The bounds α1 = T1, ..., αn = Tn are incorporated with the current bound set.
If the result does not contain the bound false, then the result becomes the new bound set, and resolution proceeds by selecting a new set of variables to instantiate (if necessary), as described above.
用简单的英语来说,在尝试类型参数的可能值时,编译器首先尝试下限,如果合适则使用下限。
在我们的例子中,约束集表示 D extends T and D extends A
,因此 T
的下限是 D
,因此 D
是第一个候选替换。
编译器然后通过假设 T = D
来验证 D
是否适合,这简化了将约束设置为 D extends D and D extends A
,两者都为真。
因此,编译器使用D
。
这段代码中,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 是否有任何规则?
Is there any rule for how type inference is done
是的,entire 18th chapter of the Java Language Specification 专门讨论这个话题:-)
and why it selects D?
我认为以下规则对此负责:
If the bound set does not contain a bound of the form G<..., αi, ...> = capture(G<...>) for all i (1 ≤ i ≤ n), then a candidate instantiation Ti is defined for each αi:
If αi has one or more proper lower bounds, L1, ..., Lk, then Ti = lub(L1, ..., Lk) (§4.10.4).
Otherwise, if the bound set contains throws αi, and the proper upper bounds of αi are, at most, Exception, Throwable, and Object, then Ti = RuntimeException.
Otherwise, where αi has proper upper bounds U1, ..., Uk, Ti = glb(U1, ..., Uk) (§5.1.10).
The bounds α1 = T1, ..., αn = Tn are incorporated with the current bound set.
If the result does not contain the bound false, then the result becomes the new bound set, and resolution proceeds by selecting a new set of variables to instantiate (if necessary), as described above.
用简单的英语来说,在尝试类型参数的可能值时,编译器首先尝试下限,如果合适则使用下限。
在我们的例子中,约束集表示 D extends T and D extends A
,因此 T
的下限是 D
,因此 D
是第一个候选替换。
编译器然后通过假设 T = D
来验证 D
是否适合,这简化了将约束设置为 D extends D and D extends A
,两者都为真。
因此,编译器使用D
。