java-8 中有界通配符的规则更改?
rule changing in bounded wildcards in java-8?
我正在学习 Java 中关于泛型的教程,定义了这个静态方法:
public static <T extends Comparable<T>> T min(T a) { ... }
并说
min(new GregorianCalendar());
无法编译,因为 GregorianCalendar extends Calendar
和 Calendar implements Comparable<Calendar>
所以它暗示 GregorianCalendar implements Comparable<Calendar>
而不是 Comparable<GregorianCalendar>
。
所以为了编译签名必须改成:
public static <T extends Comparable<? super T>> T min(T a) { ... }
这完全可以理解。该方法的第一个版本实际上不会在 java-5 中编译,但它会在 java-8 中编译! (我尝试了 5 到 8)
为什么 java-8 现在允许这样做? (因为它现在使它更加混乱)。这背后的新 "rule" 是什么?
类型推断!
JLS §18. Specifically, I'll direct you to JLS §18.2(第 678 页)中有大量关于此的信息,其中指出:
在你的情况下,让 S = GregorianCalendar
和 T = Calendar
。 This page states (during the reduction process) if S
is a sub-type of T
, then S
is considered to be of type T
(GregorianCalendar
被视为 Calendar
).
你的例子的问题是你写了
min(new GregorianCalendar());
作为一个独立的表达式。在 Java 8 之前,这将由编译器通过推断 GregorianCalendar
来处理 T
,它不满足约束“… extends Comparable<T>
”,因此它被拒绝。
从 Java 8 开始,编译器为 T
推断出 Calendar
,它满足约束条件,传递 GregorianCalendar
的实例是有效的,其中 Calendar
是预期的,所以这个例子被接受了。这就像你在以前的 Java 版本中写了 YourClass.<Calendar>min(new GregorianCalendar());
。
然而,这并没有解决 min
声明不接受 T
的 GregorianCalendar
的根本问题。虽然 Java 8 允许您编写,例如
Calendar c = min(new GregorianCalendar());
对T
使用Calendar
,对T
使用GregorianCalendar
仍然无效,例如
GregorianCalendar c = min(new GregorianCalendar());
还是会被编译器拒绝
因此,还是需要使用带通配符的声明
public static <T extends Comparable<? super T>> T min(T a) { ... }
允许呼叫者像
一样使用它
GregorianCalendar c = min(new GregorianCalendar());
我正在学习 Java 中关于泛型的教程,定义了这个静态方法:
public static <T extends Comparable<T>> T min(T a) { ... }
并说
min(new GregorianCalendar());
无法编译,因为 GregorianCalendar extends Calendar
和 Calendar implements Comparable<Calendar>
所以它暗示 GregorianCalendar implements Comparable<Calendar>
而不是 Comparable<GregorianCalendar>
。
所以为了编译签名必须改成:
public static <T extends Comparable<? super T>> T min(T a) { ... }
这完全可以理解。该方法的第一个版本实际上不会在 java-5 中编译,但它会在 java-8 中编译! (我尝试了 5 到 8)
为什么 java-8 现在允许这样做? (因为它现在使它更加混乱)。这背后的新 "rule" 是什么?
类型推断!
JLS §18. Specifically, I'll direct you to JLS §18.2(第 678 页)中有大量关于此的信息,其中指出:
在你的情况下,让 S = GregorianCalendar
和 T = Calendar
。 This page states (during the reduction process) if S
is a sub-type of T
, then S
is considered to be of type T
(GregorianCalendar
被视为 Calendar
).
你的例子的问题是你写了
min(new GregorianCalendar());
作为一个独立的表达式。在 Java 8 之前,这将由编译器通过推断 GregorianCalendar
来处理 T
,它不满足约束“… extends Comparable<T>
”,因此它被拒绝。
从 Java 8 开始,编译器为 T
推断出 Calendar
,它满足约束条件,传递 GregorianCalendar
的实例是有效的,其中 Calendar
是预期的,所以这个例子被接受了。这就像你在以前的 Java 版本中写了 YourClass.<Calendar>min(new GregorianCalendar());
。
然而,这并没有解决 min
声明不接受 T
的 GregorianCalendar
的根本问题。虽然 Java 8 允许您编写,例如
Calendar c = min(new GregorianCalendar());
对T
使用Calendar
,对T
使用GregorianCalendar
仍然无效,例如
GregorianCalendar c = min(new GregorianCalendar());
还是会被编译器拒绝
因此,还是需要使用带通配符的声明
public static <T extends Comparable<? super T>> T min(T a) { ... }
允许呼叫者像
一样使用它GregorianCalendar c = min(new GregorianCalendar());