Arrays类中的sort方法为什么不定义为接收一个Comparable[]数组
有人认为,将Arrays类中的sort方法定义为接受一个Comparable[]数组就可以在使用元素类型没有实现Comarable接口的数组作为参数调用sort方法时,由编译器给出错误报告,但事实并非如此,为什么呢?
参考:https://www.zhihu.com/question/67693996/answer/255459062
http://www.imooc.com/wenda/detail/551503
1、数组是协变的
数组是协变的,即如果Sub为Super的子类型,那么数组类型Sub[]就是Super[]的子类型。可以将一个Comparable[]数组转换为Object[],反之则不行。如果Arrays.sort()方法声明为接收Comparable[]数组,那么在一开始调用的时候就要实例化一个Comparable[]数组或者兼容数组,这就会引起一种不便:即Java的部分API拿到就是Object[](比如Collection的toArray()方法),而即使你的Object[]内部对象的实际类型全部是Comparable兼容的,也不能把Object[]类型转换成Comparable[],因为Java认为它们类型不同,如果你调用某个API意外地得到了Object[]类型而又需要排序的话,你就得不得不复制一个新的Comparable[]数组出来排序,而这个是没有任何必要的,所以Java就这样设计API了。
2、泛型数组是非法的
Comparable<T>[]
泛型数组是非法的,而使用原生态类型是不安全的,应该尽量避免。
首先:创建泛型、参数化类型或者类型参数的数组是非法的,以下创建数组表达式没有一个是合法的:
new List<E>[], new List<String>[], new E[]
下文引用Effective Java的内容解释一下为什么泛型数组是非法的.
List<String>[] StringLists = new List<String>[1]; // (1)
List<Integer> intList = List.of(42); // (2)
Object[] objects = StringLists; // (3)
objects[0] = intList; // (4)
String s = stringLists[0].get(0); // (5)
假设第一行是合法的,它创建了一个泛型数组。第二行创建并初始化了一个包含单个元素的List<Integer>
.第三行将List<String>
数组保存到一个Object数组变量中,这是合法的,因为数组是协变的。第四行将List<Integer>
保存到Object数组里面唯一的元素中,这是可以的,因为泛型是通过擦除实现的:List<Integer>
实例运行时类型只是List,List<String>[]
实例的运行时类型则是List[],第五行中我们从这个数组里唯一的列表中获取了唯一的元素。编译器自动地将获取到的元素转换成String,但它是一个Integer,因此,我们在运行时得到了一个ClassCastEcxeption异常。为了防止出现这种情况,(创建泛型数组的)第一行必须产生一条变异时的错误。
3、Collections.sort()方法
Collections.sort()方法:此方法对参数做了限制,<T extends Comparable<? super T>>
,
其内部实现也是调用了Arrays.sort()方法。
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}
default void sort(Comparator<? super E> c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator<E> i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}
ps:第一篇技术博客,也是临时起意,想记录一下,大部分都是抄的,就当是平常的做了个笔记,自己巩固一遍,也方便日后复习。