Comparable和Comparator区分以及使用

前言

Comparable和Comparator都是java提供的一个接口,它们应用的场景是在数组的排序中,比如Collection这个接口提供了一个sort的方法,里面可以使用这两个接口的实现类来完成集合排序,那么这两个接口有什么不一样的地方呢,什么情况应该选择什么样的接口?我们来简单的认识一下它们
Comparable接口
Comparable: public int compareTo(T o); 这个Comparable是一般让一个POJO类的作为其实现类,将this对象与T o对象比较,如果return0,则表示它们相等,如果>0 则表示this对象比T o 对象大,如果 < 0 则 this对象比T o 小
Comparator接口
Comparator: int compare(T o1, T o2);Comparator是不需要对POJO提供接口的,而是重新写一个Comparator的新的实现类作为比较器,当做sort的一个参数,sort函数的形参专门有接口这些比较器的类型(这种写法很常见,实现代码重用、扩展,也就是策略模式了)。它和Comparable比较规则一样,这里o1 与 o2比较,如果返回值 = 0 则表示o1 == o2 ; 如果 > 0 则表示 o1 > o2; 如果 < 0 则 o1 < o2;


为什么写这篇文章

我一直对Comparable 与 Comparator很疑惑,因为我们客户端程序员只需要按照规则构建好POJO类或者新的比较器,然后调用类设计者提供的给我们的公共接口方法就行了,具体如何做对我们都是隐藏的。为什么要按照这样的规则构建而一无所知,不知道它可以应用到什么场景中,会不会出错,同时也很好奇它的实现原理。为了加深印象,不用记忆的这么痛苦,我花了一点时间去仔细的理清楚它们的关系,在此写这篇文章来加深自身的基础功。由于时间的关系与自身的水平原因,如果有误导的地方请多指教


正文

在前言中我已经讲到了它们两个都是一个接口,我们客户端程序员只需要提供一个具体的实现类即可,但是它们应用到哪里呢? 里面如何调用呢?这些代码我们都没法知道,因为类设计者已经帮我们实现了并提供给我们公共接口方法调用来完成我们所需要的功能,下面我打算从这两个接口的实现类如何调用这个方面入手来加深对它们的理解
我简单的看了一下,在Collection.sort 、Arrays.sort 还是其他的地方都有对这两个接口使用,这里我从Arrays.sort来看看它们是如何调用的

Comparable在集合中的应用

public static void sort(Object[] a) {
        if (LegacyMergeSort. userRequested)
            legacyMergeSort(a);
        else
            ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
}

这里Object已经是POJO实现Comparable接口的对象,从这个源码中我随便点进了这行代码ComparableTimSort.sort(a , 0, a .length , null, 0, 0); 进入到sort里面以后我发现里面有一个叫折半插入排序的算法
private static void binarySort(Object[] a, int lo , int hi, int start)
这个折半插入排序算法就调用了Comparable的compareTo方法进行比较两个对象的大小,从而来决定左边界与右边界具体的移动

    while (left < right ) {
                int mid = ( left + right) >>> 1;
                if ( pivot.compareTo( a[ mid]) < 0)
                    right = mid;
                else
                    left = mid + 1;
    }

pivot是一个对象,a[mid]另外一个对象。从这里我知道了原来对象是不能通过 > < =这样的运算符做比较的,只能通过客户端程序员实现这儿compareTo的方法来比较两个对象的大小。到此我觉得可以退出这些复杂的逻辑了,具体如何实现list的排序不是本文讲解的范围了

Comparator在集合中的应用

Comparator的调用和上边几乎是一样的,不过它使用的是这半插入排序的一个重载方法

private static <T> void binarySort(T[] a, int lo, int hi, int start,
                                       Comparator<? super T> c)
          while (left < right ) {
                int mid = ( left + right) >>> 1;
                if ( c.compare( pivot, a[ mid]) < 0)
                    right = mid;
                else
                    left = mid + 1;
 }

这里用Comparator来接收各种Comparator的实现类,利用向上转型,以及多态来实现代码重用,它遵循着策略设计模式的规则。我看到上面 c.compare( pivot, a[ mid])用来比较两个对象的大小,从而决定左右边界的移动

总结

当我们要对一个集合数组做排序的时候,我们可以用两种方法来完成,向排序方法提供实现Comparable与Comparator类的对象,具体如何排序,以及如何实现,由封装的方法决定。这里注意一点就是排序的方法一定要实现对这两个接口的支持(也就是说里面会存在具体调用的过程),可以写重载排序方法分别完成两个接口提供的方法调用。可以参考文章《java实现折半插入排序算法》,最后贴出的代码有对这两个接口进行调用的排序算法


参考资料

Comparable与Comparator的区别
http://blog.csdn.net/mageshuai/article/details/3849143

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值