Collections.sort()声明:为什么<! - ?超级T - >而不是<t>

时间:2016-03-01 05:12:59

标签: java generics collections comparable

为什么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)
  • 我知道他们俩都会达到同样的目的;那么框架开发人员为什么要使用第一个选项?
  • 或者这些声明真的不同吗?

3 个答案:

答案 0 :(得分:19)

您提议的签名可能适用于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。但是,Java 7规范不允许这样的推断。因此,此代码可以使用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中的类型推断得到了极大的改进。现在专用于单独的JLS chapter 18,而在Java-7中,规则were更加简单。

答案 1 :(得分:9)

// 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 A implements Comparable<Object> { ... }

然后,如果你有

List<A> list = ... ;
sort0(list); // works
sort1(list); // fails

sort1失败的原因是没有类型T既可以与自身相比,也可以是列表中的超类型。 s型。

事实证明,类A格式不正确,因为Comparable的对象需要满足某些要求。特别是逆转比较应该反转结果的符号。我们可以将A的实例与Object进行比较,反之亦然,因此违反了此​​要求。但请注意,这是Comparable语义的要求,并不是由类型系统强加的。仅考虑类型系统,两个sort声明确实不同。

答案 2 :(得分:4)

它们有所不同,因为? super T的限制性比T更少。它是Lower Bounded Wildcard(链接的Java教程,部分说)

  

术语List<Integer>List<? super Integer>更具限制性,因为前者仅匹配类型Integer的列表,而后者匹配任何类型的列表Integer的超类型Integer 1}}。

T替换为T,这意味着java.lang.Object a OrderItem::whereBetween( 'created_at', [ DB::raw("CONVERT_TZ('$date 09:00:00', '+00:00', '-06:00')"), DB::raw("CONVERT_TZ('$date 18:00:00', '+00:00', '-06:00')") ] )->count();