了解Java中的Collections.reverseOrder()方法
考虑了解Java中的Collections.reverseOrder()方法,java,generics,Java,Generics,考虑数组类中排序方法的重载定义之一: public static <T> void sort(T[] a, Comparator<? super T> c) private static class ReverseComparator implements Comparator<Comparable<Object>>, Serializable { private static final long serialVersionU
数组
类中排序
方法的重载定义之一:
public static <T> void sort(T[] a, Comparator<? super T> c)
private static class ReverseComparator
implements Comparator<Comparable<Object>>, Serializable {
private static final long serialVersionUID = 7207038068494060240L;
static final ReverseComparator REVERSE_ORDER = new ReverseComparator();
public int compare(Comparable<Object> c1, Comparable<Object> c2) {
return c2.compareTo(c1);
}
private Object readResolve() { return reverseOrder(); }
}
反向比较器
等级:
public static <T> void sort(T[] a, Comparator<? super T> c)
private static class ReverseComparator
implements Comparator<Comparable<Object>>, Serializable {
private static final long serialVersionUID = 7207038068494060240L;
static final ReverseComparator REVERSE_ORDER = new ReverseComparator();
public int compare(Comparable<Object> c1, Comparable<Object> c2) {
return c2.compareTo(c1);
}
private Object readResolve() { return reverseOrder(); }
}
私有静态类反向比较器
实现可序列化的比较器{
私有静态最终长serialVersionUID=7207038068494060240L;
静态最终反向比较器反向顺序=新反向比较器();
公共整数比较(可比c1,可比c2){
返回c2。比较到(c1);
}
私有对象readResolve(){return reverseOrder();}
}
我的问题是:为什么Collections.reverseOrder()
是泛型的?为什么只是ReverseComparator.反向订单不能返回
当然,我们可以显式地指定调用集合的类型。reverseOrder()
。但是在这种情况下,简单的Collections.reverseOrder()
有什么好处呢
我在那里发现了一个非常有用的讨论:
但这并不能回答我的问题
我还感兴趣的是sort
方法如何使用compare
方法,该方法来自ReverseComparator
类。正如我们所看到的,compare
采用compariable
类型的参数。如果我们对实现compariable
的对象数组进行排序,其中T
例如是Integer
?我们无法使用compare
调用compare
,因为compariable
未强制转换为compariable
为什么Collections.reverseOrder()是泛型的
此函数是通用函数,以避免将结果强制转换为特定的可比类型。(你可能会说你不在乎,因为你根本就不投,在这种情况下,这告诉我们,你没有启用足够的警告。)
为什么我们不能简单地返回ReverseComparator.REVERSE\u订单
一个原因是因为ReverseComparator.REVERSE\u ORDER
是包私有的,所以您不能从包外部访问它。这反过来又引出了一个问题“为什么它是包私有的?”主要是因为这满足了纯粹主义者,当他们看到成员变量被直接访问时,即使它们是最终的,他们也会退缩,但实际上我不会在这种情况下责备他们,因为访问器提供了二进制级别的前向兼容性,这在应用程序代码中可能是完全不必要的,但在语言运行库中却是必要的。而ReverseComparator
是java运行时的一部分
但是一个更重要的原因是因为Collections.reverseOrder()
为您转换到(Comparator)
,这样您就不必自己做了。(同样,如果您没有发现问题,那是因为您没有启用足够的警告,这意味着您需要重新考虑您的做法。)
简而言之,如果您尝试执行以下操作:
Comparator<MyObject> myComparator = ReverseComparator.REVERSE_ORDER;
正如我们所看到的,compare接受可比较类型的参数。如果我们对实现Compariable的对象数组进行排序,例如T是整数,会怎么样?我们不能调用compare with Compariable,因为Compariable不属于Compariable
好吧,我知道你真正的问题是什么了。欢迎来到java泛型和类型擦除的奇妙世界。我将尝试解释,但一定要查找“类型擦除”一词,以便充分理解该概念
在java中,泛型是事后才被引入语言的。出于这个原因,它们必须以这样一种方式实现,即泛型识别代码将向后兼容不具有泛型识别功能的旧代码。解决方案是一种称为类型擦除的技巧,这基本上意味着编译后泛型信息被完全剥离。这意味着在字节码级别,比较器
和比较器
和比较器
是一回事。没什么区别。这使java运行时能够实现单个类,该类充当任何对象的反向比较器。它实际上不是一个比较器
,它是一个比较器
,因为它所做的只是反转比较的方向,所以它并不真正关心被比较对象的性质
因此,在java中,如果您真的知道自己在做什么,您可以自由地将泛型类的实例强制转换为同一类的实例,但使用不同的泛型参数。在本例中,java运行时的创建者正在将Comparator
转换为Comparator
,这实际上可以在以后分配给Comparator
,这很好
不过,此强制转换很棘手,因为编译器必须相信您确实知道自己在做什么,因此默认情况下,编译器会对此类强制转换发出“未经检查的赋值”警告,然后我们表明我们知道使用@SuppressWarnings(“未经检查”)
注释所做的事情
Collections.reverseOrder()
让您不用担心所有这些。这都是关于类型擦除的。请记住,在运行时没有可比的
,只有可比的。因此,例如,REVERSE\u COMPARATOR
的compare
方法可用于两个String
实例。它在运行时不会导致ClassCastException
,因为String
实现了Comparable
,而在运行时这只是Comparable
但是,方法reverseComparator
必须是泛型的,因为否则用户必须将返回的对象强制转换为适当的类型才能使用。例如,考虑这个代码,比较器的类型与<代码> ReaveSeX比较器< /C> >的类型相同。
Comparator<Comparable<Object>> comparator = Collections.reverseOrder();
String[] arr = {"A", "B", "C"};
Arrays.sort(arr, comparator); // Doesn't compile.
这产生
Comparator<MyObject> myComparator = Collections.reverseOrder();
Comparator<Comparable<Object>> comparator = Collections.reverseOrder();
String[] arr = {"A", "B", "C"};
Arrays.sort(arr, comparator); // Doesn't compile.
Comparator<Comparable<Object>> comparator = Collections.reverseOrder();
String[] arr = {"A", "B", "C"};
Arrays.sort(arr, (Comparator<String>) (Object) comparator);
System.out.println(Arrays.toString(arr)); // prints [C, B, A]
Collections.emptySet()
Optional.empty()
Comparator.naturalOrder()
Collections.emptyListIterator()