先看下面一段代码:
List<String> list=new ArrayList<>(); list.add("x"); list.add("a"); list.add("c"); list.add("y");
Collections.sort(list); System.out.println(list);
输出结果:
[a, c, x, y]
这是一段非常简单的使用集合工具类排序的代码,这里有个问题,我们什么也没指定,默认就按字母升序排了,这是为什么?通过查看String类的源码,我们能够发现其实现了三个接口,如下:
class String implements java.io.Serializable, Comparable<String>, CharSequence
注意其中的第二个接口Comparable,实现了该接口的类,相当于默认定义了该类在集合里面的自然排序的方式。
Java里面关于对象排序一般离不开两个接口:Comparable和Comparator,那么它们两者有什么区别呢?
Comparable:提供自然排序的定义,比如String类提供了字母序,Integer类提供了大小序,等在Java中基本类型的包装类都提供了自然排序的默认的实现,这也是我们为什么能直接使用Collections.sort函数来获取一个排序的结果,那是因为这些类都必须实现了Comparable接口才可以,如果你自定义一个类,没有实现该接口,直接尝试调用这个方法会直接编译错误。
Comparator:非自然排序的接口,可以不需要改动原类,从外部自定义一个排序规则来实现排序。比如上面的String类,我们默认调用Collections.sort来对集合进行按字符串升序,但如果我们想要一个降序的结果集应该怎么办?有的同学可能已经想到了使用集合的Collections.reverse()方法就可以,这样确实可以,更优雅的办法我们的可以使用Comparator接口,来定义一个外部排序规则,如下:
class StringComparator implements Comparator<String>{
@Override public int compare(String o1, String o2) { return -o1.compareTo(o2); } }
然后调用集合工具类的第二种的排序方法:
Collections.sort(list, new StringComparator());
输出结果如下:
[y, x, c, a]
当然如果用了Java8,上面可以不用新定义一个排序规则类,可以直接使用lambda函数使得代码更简洁。
什么时候应该用Comparable或者Comparator?
如果你想给你自定义的类提供默认的自然顺序,那么Comparable是一个好的选择。如果对类里面自带的自然排序不满意,而又不能修改其源代码的情况下,使用Comparator就比较合适。此外使用Comparator可以避免添加额外的代码与我们的目标类耦合,同时可以定义多种排序规则,这一点是Comparable接口没法做到的,从灵活性和扩展性讲Comparator更优,故在面对自定义排序的需求时,可以优先考虑使用Comparator接口。