欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。


欢迎跳转到本文的原文链接:https://honeypps.com/java/comparable-and-comparator-analysis/

  今天博主在翻阅TreeMap的源码,发现其键必须是实现Comparable或者Comparator的接口时产生了一些兴趣,比如在TreeMap中的put方法分别对Comparable和Comparator接口分别进行处理。那么疑问就来了,Comparable和Comparator接口的区别是什么,Java中为什么会存在两个类似的接口?

  Comparable和Comparator接口都是用来比较大小的,首先来看一下Comparable的定义:

 package java.lang;
import java.util.*;
public interface Comparable<T> {public int compareTo(T o);
}

  Comparator的定义如下:

package java.util;
public interface Comparator<T> {int compare(T o1, T o2);boolean equals(Object obj);
}

  Comparable对实现它的每个类的对象进行整体排序。这个接口需要类本身去实现(这句话没看懂?没关系,接下来看个例子就明白了)。若一个类实现了Comparable 接口,实现 Comparable 接口的类的对象的 List 列表 ( 或数组)可以通过 Collections.sort(或 Arrays.sort)进行排序。此外,实现 Comparable 接口的类的对象 可以用作 “有序映射 ( 如 TreeMap)” 中的键或 “有序集合 (TreeSet)” 中的元素,而不需要指定比较器。
  举例(类Person1实现了Comparable接口)

package collections;public class Person1 implements Comparable<Person1>
{private int age;private String name;public Person1(String name, int age){this.name = name;this.age = age;}@Overridepublic int compareTo(Person1 o){return this.age-o.age;}@Override public String toString(){return name+":"+age;}
}

  可以看到Person1实现了Comparable接口中的compareTo方法。实现Comparable接口必须修改自身的类,即在自身类中实现接口中相应的方法。
  测试代码:

     Person1 person1 = new Person1("zzh",18);Person1 person2 = new Person1("jj",17);Person1 person3 = new Person1("qq",19);List<Person1> list = new ArrayList<>();list.add(person1);list.add(person2);list.add(person3);System.out.println(list);Collections.sort(list);System.out.println(list);

  输出结果:

[zzh:18, jj:17, qq:19]
[jj:17, zzh:18, qq:19]

  如果我们的这个类无法修改,譬如String,我们又要对其进行排序,当然String中已经实现了Comparable接口,如果单纯的用String举例就不太形象。对类自身无法修改这就用到了Comparator这个接口(策略模式)。

public final class Person2
{private int age;private String name;public Person2(String name, int age){this.name = name;this.age = age;}@Override public String toString(){return name+":"+age;}//getter and setter方法省略....
}

  如类Person2,这个类已经固定,无法进行对其类自身的修改,也修饰词final了,你也别想继承再implements Comparable,那么此时怎么办呢?在类的外部使用Comparator的接口。如下测试代码:

     Person2 p1 = new Person2("zzh",18);Person2 p2 = new Person2("jj",17);Person2 p3 = new Person2("qq",19);List<Person2> list2 = new ArrayList<Person2>();list2.add(p1);list2.add(p2);list2.add(p3);System.out.println(list2);Collections.sort(list2,new Comparator<Person2>(){@Overridepublic int compare(Person2 o1, Person2 o2){if(o1 == null || o2 == null)return 0;return o1.getAge()-o2.getAge();}});System.out.println(list2);

  输出结果:

[zzh:18, jj:17, qq:19]
[jj:17, zzh:18, qq:19]

  这里(public static <T> void sort(List<T> list, Comparator<? super T> c) )采用了内部类的实现方式,实现compare方法,对类Person2的list进行排序。
  再譬如博主遇到的真实案例中,需要对String进行排序,且不区分大小写,我们知道String中的排序是字典排序,譬如:A a D排序之后为A D a,这样显然不对,那么该怎么办呢?同上(下面代码中的list是一个String的List集合):

        Collections.sort(list, new Comparator<String>(){@Overridepublic int compare(String o1, String o2){if(o1 == null || o2 == null)return 0;return o1.toUpperCase().compareTo(o2.toUpperCase());}});

  这样就可以实现不区分大小进行排序String的集合了,是不是很方便~


  细心的同学可能会有疑问,明明在Comparator接口中定义了两个方法,为什么继承的时候只实现了一个方法,难道要颠覆我对Java接口常识的理解了嚒?
  实际上,我们知道当一个类没有显式继承父类的时候,会有一个默认的父类,即java.lang.Object,在Object类中有一个方法即为equals方法,所以这里并不强制要求实现Comparator接口的类要实现equals方法,直接调用父类的即可,虽然你显式的实现了equals()方法 will be a better choice~


  在《Effective Java》一书中,作者Joshua Bloch推荐大家在编写自定义类的时候尽可能的考虑实现一下Comparable接口,一旦实现了Comparable接口,它就可以跟许多泛型算法以及依赖于改接口的集合实现进行协作。你付出很小的努力就可以获得非常强大的功能。
  事实上,Java平台类库中的所有值类都实现了Comparable接口。如果你正在编写一个值类,它具有非常明显的内在排序关系,比如按字母顺序、按数值顺序或者按年代顺序,那你就应该坚决考虑实现这个接口。
  compareTo方法不但允许进行简单的等同性进行比较,而且语序执行顺序比较,除此之外,它与Object的equals方法具有相似的特征,它还是一个泛型。类实现了Comparable接口,就表明它的实例具有内在的排序关系,为实现Comparable接口的对象数组进行排序就这么简单: Arrays.sort(a);
  对存储在集合中的Comparable对象进行搜索、计算极限值以及自动维护也同样简单。列如,下面的程序依赖于String实现了Comparable接口,它去掉了命令行参数列表中的重复参数,并按字母顺序打印出来:

public class WordList{public static void main(String args[]){Set<String> s = new TreeSet<String>();Collections.addAll(s,args);System.out.println(s);}
}

  Comparable 是排序接口;若一个类实现了 Comparable 接口,就意味着 “该类支持排序”。而 Comparator 是比较器;我们若需要控制某个类的次序,可以建立一个 “该类的比较器” 来进行排序。
  前者应该比较固定,和一个具体类相绑定,而后者比较灵活,它可以被用于各个需要比较功能的类使用。可以说前者属于 “静态绑定”,而后者可以 “动态绑定”。
  我们不难发现:Comparable 相当于 “内部比较器”,而 Comparator 相当于 “外部比较器”。

欢迎跳转到本文的原文链接:https://honeypps.com/java/comparable-and-comparator-analysis/


欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。


Comparable与Comparator浅析相关推荐

  1. 浅析 Comparable和 Comparator的区别

    简介 Comparable和 Comparator都是java.util包下的两个接口,从字面上看这两个接口都是用来做比较用的,但是jdk里面不可能定义两个功能相同的接口,所以他们肯定有不同的用处. ...

  2. Java 中 Comparable 和 Comparator 比较

    为什么80%的码农都做不了架构师?>>>    本文,先介绍Comparable 和Comparator两个接口,以及它们的差异:接着,通过示例,对它们的使用方法进行说明. Comp ...

  3. Java 解惑:Comparable 和 Comparator 的区别

    读完本文你将了解到: Comparable 自然排序 Comparator 定制排序 总结 Java 中为我们提供了两种比较机制:Comparable 和 Comparator,他们之间有什么区别呢? ...

  4. 对象比较:Comparable 和 Comparator

    java中我们如何给对象排序?这就必须借助Comparator 或 Comparable.有了他们就意味着你可用实现对象之间的比较.也就可用做到排序了. Comparable Comparable 也 ...

  5. Java核心API -- 7(Iterator迭代器、Comparable、Comparator比较器)

    1. Iterator迭代器 所有Collection的实现类都实现了iterator方法,该方法返回一个Iterator接口类型的对象,用于实现对集合元素迭代的便利.在java.util包下. 1) ...

  6. java compareto方法怎么排序的_深入理解Java中Comparable和Comparator排序

    本文有牛旦教育原创,头条首发,转载注明来源. 如何为需要的排序算法选择正确的接口?通过本文的分析讲解,我们会找到答案参考答案. 程序员经常需要将数据库中的元素排序为集合.数组或映射.在Java中,我们 ...

  7. Java中Comparable和Comparator区别小结

    阅读目录 一.Comparable简介 二.Comparator简介 三.Comparable和Comparator区别比较 回到顶部 一.Comparable简介 Comparable是排序接口.若 ...

  8. comparable和comparator比较

      今天在翻阅TreeMap的源码,发现其键必须是实现Comparable或者Comparator的接口时产生了一些兴趣,比如在TreeMap中的put方法分别对Comparable和Comparat ...

  9. Java中Comparable与Comparator的区别

    一.概述 Comparable和Comparator都是用来实现集合中元素的比较.排序的. Comparable是在集合内部定义的方法实现的排序,位于java.util下. Comparator是在集 ...

最新文章

  1. Access应用日志一
  2. 哈希查找解决地址冲突的两种最常见方法(线性探测再散列,链地址法)C++实现
  3. 2.11 计算机视觉现状-深度学习第四课《卷积神经网络》-Stanford吴恩达教授
  4. yum 方式安装nginx
  5. LiveVideoStackCon 2020北京站 | 参会指南
  6. BUUCTF-- Linux Labs 1---SSH远程登陆
  7. mysql 查询auto_increment_MySQL查询数据表的Auto_Increment(自增id)
  8. anaconda下载的python在哪_python包管理器anaconda介绍安装和使用
  9. 牛客网 牛客小白月赛1 C.分元宵-快速幂
  10. 将Vim打造成Python快速开发环境(一)
  11. pc套件 无法连接pc CDC Comms Interface
  12. Excel2016右键新建工作表,打开时提示“因为文件格式或文件扩展名无效。请确定文件未损坏,并且文件扩展名与文件的格式匹配。”的解决办法
  13. 虚拟机设置共享文件夹之后看不见文件(失败合集+成功分享)
  14. tplink无线路由dns服务器,TPLINK无线路由器如何设置DNS服务器的DNS服务器地址,TPLINK无线路由器的地址 | 192.168.1.1手机登陆...
  15. MongoDB入门+深入(二)--项目实战
  16. POI 操作word
  17. oeasy教您玩转 linux 010213 中文 fcitx
  18. php语句连接,php – 内连接选择语句
  19. python作业——SVM预测交通流量
  20. Markdowm编辑器推荐和Emoji 表情

热门文章

  1. 如何联网获取北京时间
  2. HX720/HX711 数据采集及处理姿态解析(公式及源码)
  3. 探析“Java序列化”之serialVersionUID
  4. solidity智能合约[37]-以太坊虚拟机数据存储
  5. Easy Problem 2 奇妙的数字
  6. android常见异常总结
  7. MQTT协议笔记之mqtt.io项目TCP协议支持
  8. js 层 分页显示选择用户名
  9. TCP中的Flag options
  10. POJ - 2559 Largest Rectangle in a Histogram(笛卡尔树,单调栈实现)