Collections.sort() 声明:为什么 <?超级 T> 而不是 <T>
Collections.sort() declaration: why <? super T> rather than <T>
为什么 Collections.sort(List<T>)
有签名:
public static <T extends Comparable<? super T>> void sort(List<T> list)
而不是:
public static <T extends Comparable<T>> void sort(List<? extends T> list)
- 据我了解,它们的用途相同;那么为什么框架开发人员使用第一个选项?
- 或者这些声明真的不同吗?
它们的不同之处在于 ? super T
比 T
的限制更少。这是一个 Lower Bounded Wildcard(链接的 Java 教程部分说)
The term List<Integer>
is more restrictive than List<? super Integer>
because the former matches a list of type Integer
only, whereas the latter matches a list of any type that is a supertype of Integer
.
将Integer
替换为T
,这意味着一个T
或一个java.lang.Object
.
您提议的签名可能适用于 Java-8。然而,在之前的 Java 版本中,类型推断并不是那么聪明。假设您有 List<java.sql.Date>
。请注意,java.sql.Date
扩展了 java.util.Date
,它实现了 Comparable<java.util.Date>
。当你编译
List<java.sql.Date> list = new ArrayList<>();
Collections.sort(list);
它在 Java-7 中完美运行。这里 T
被推断为 java.sql.Date
实际上是 Comparable<java.util.Date>
即 Comparable<? super java.sql.Date>
。但是让我们试试你的签名:
public static <T extends Comparable<T>> void sort(List<? extends T> list) {}
List<java.sql.Date> list = new ArrayList<>();
sort(list);
这里T
应该推断为java.util.Date
。然而 Java7 规范不允许这样的推断。因此这段代码可以用 Java-8 编译,但在 Java-7:
下编译时失败
Main.java:14: error: method sort in class Main cannot be applied to given types;
sort(list);
^
required: List<? extends T>
found: List<Date>
reason: inferred type does not conform to declared bound(s)
inferred: Date
bound(s): Comparable<Date>
where T is a type-variable:
T extends Comparable<T> declared in method <T>sort(List<? extends T>)
1 error
类型推断在 Java-8 中得到了极大改进。分离JLSchapter 18 is dedicated to it now, while in Java-7 the rules were简单多了。
// 0
public static <T extends Comparable<? super T>> void sort0(List<T> list)
// 1
public static <T extends Comparable<T>> void sort1(List<? extends T> list)
这些签名不同是因为它们对 T
类型和 Comparable
的类型参数之间的关系提出了不同的要求 T
.
假设你有这个 class:
class A implements Comparable<Object> { ... }
那么如果你有
List<A> list = ... ;
sort0(list); // works
sort1(list); // fails
sort1
失败的原因是 没有 类型 T
可以与自身相比较,或者是超类型,列表的类型。
事实证明 class A
格式不正确,因为 Comparable
的对象需要满足某些要求。特别是反转比较应该反转结果的符号。我们可以将 A
的实例与 Object
的实例进行比较,但反之则不行,因此违反了此要求。但请注意,这是 Comparable
的 语义 的要求,而不是类型系统强加的。仅考虑类型系统,两个 sort
声明确实不同。
为什么 Collections.sort(List<T>)
有签名:
public static <T extends Comparable<? super T>> void sort(List<T> list)
而不是:
public static <T extends Comparable<T>> void sort(List<? extends T> list)
- 据我了解,它们的用途相同;那么为什么框架开发人员使用第一个选项?
- 或者这些声明真的不同吗?
它们的不同之处在于 ? super T
比 T
的限制更少。这是一个 Lower Bounded Wildcard(链接的 Java 教程部分说)
The term
List<Integer>
is more restrictive thanList<? super Integer>
because the former matches a list of typeInteger
only, whereas the latter matches a list of any type that is a supertype ofInteger
.
将Integer
替换为T
,这意味着一个T
或一个java.lang.Object
.
您提议的签名可能适用于 Java-8。然而,在之前的 Java 版本中,类型推断并不是那么聪明。假设您有 List<java.sql.Date>
。请注意,java.sql.Date
扩展了 java.util.Date
,它实现了 Comparable<java.util.Date>
。当你编译
List<java.sql.Date> list = new ArrayList<>();
Collections.sort(list);
它在 Java-7 中完美运行。这里 T
被推断为 java.sql.Date
实际上是 Comparable<java.util.Date>
即 Comparable<? super java.sql.Date>
。但是让我们试试你的签名:
public static <T extends Comparable<T>> void sort(List<? extends T> list) {}
List<java.sql.Date> list = new ArrayList<>();
sort(list);
这里T
应该推断为java.util.Date
。然而 Java7 规范不允许这样的推断。因此这段代码可以用 Java-8 编译,但在 Java-7:
Main.java:14: error: method sort in class Main cannot be applied to given types;
sort(list);
^
required: List<? extends T>
found: List<Date>
reason: inferred type does not conform to declared bound(s)
inferred: Date
bound(s): Comparable<Date>
where T is a type-variable:
T extends Comparable<T> declared in method <T>sort(List<? extends T>)
1 error
类型推断在 Java-8 中得到了极大改进。分离JLSchapter 18 is dedicated to it now, while in Java-7 the rules were简单多了。
// 0
public static <T extends Comparable<? super T>> void sort0(List<T> list)
// 1
public static <T extends Comparable<T>> void sort1(List<? extends T> list)
这些签名不同是因为它们对 T
类型和 Comparable
的类型参数之间的关系提出了不同的要求 T
.
假设你有这个 class:
class A implements Comparable<Object> { ... }
那么如果你有
List<A> list = ... ;
sort0(list); // works
sort1(list); // fails
sort1
失败的原因是 没有 类型 T
可以与自身相比较,或者是超类型,列表的类型。
事实证明 class A
格式不正确,因为 Comparable
的对象需要满足某些要求。特别是反转比较应该反转结果的符号。我们可以将 A
的实例与 Object
的实例进行比较,但反之则不行,因此违反了此要求。但请注意,这是 Comparable
的 语义 的要求,而不是类型系统强加的。仅考虑类型系统,两个 sort
声明确实不同。