了解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()