来吧,一文彻底搞懂Java中的Comparable和Comparator
大家好,我是沉默王二,今天在逛 programcreek 的时候,我发现了一些专注细节但价值连城的主题。比如说:Java 的 Comparable 和 Comparator 是兄弟俩吗?像这类灵魂拷问的主题,非常值得深入地研究一下。

Comparable 和 Comparator 是 Java 的两个接口,从名字上我们就能够读出来它们俩的相似性:以某种方式来比较两个对象。但它们之间到底有什么区别呢?请随我来,打怪进阶喽!
01、Comparable
Comparable 接口的定义非常简单,源码如下所示。
public interface Comparable<T> {
int compareTo(T t);
}
如果一个类实现了 Comparable 接口(只需要干一件事,重写 compareTo() 方法),就可以按照自己制定的规则将由它创建的对象进行比较。下面给出一个例子。
public class Cmower implements Comparable<Cmower> {
private int age;
private String name;
public Cmower(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public int compareTo(Cmower o) {
return this.getAge() - o.getAge();
}
public static void main(String[] args) {
Cmower wanger = new Cmower(19,"沉默王二");
Cmower wangsan = new Cmower(16,"沉默王三");
if (wanger.compareTo(wangsan) < 0) {
System.out.println(wanger.getName() + "比较年轻有为");
} else {
System.out.println(wangsan.getName() + "比较年轻有为");
}
}
}
在上面的示例中,我创建了一个 Cmower 类,它有两个字段:age 和 name。Cmower 类实现了 Comparable 接口,并重写了 compareTo() 方法。
程序输出的结果是“沉默王三比较年轻有为”,因为他比沉默王二小三岁。这个结果有什么凭证吗?
凭证就在于 compareTo() 方法,该方法的返回值可能为负数,零或者正数,代表的意思是该对象按照排序的规则小于、等于或者大于要比较的对象。如果指定对象的类型与此对象不能进行比较,则引发 ClassCastException 异常(自从有了泛型,这种情况就少有发生了)。
02、Comparator
Comparator 接口的定义相比较于 Comparable 就复杂的多了,不过,核心的方法只有两个,来看一下源码。
public interface Comparator<T> {
int compare(T o1, T o2);
boolean equals(Object obj);
}
第一个方法 compare(T o1, T o2) 的返回值可能为负数,零或者正数,代表的意思是第一个对象小于、等于或者大于第二个对象。
第二个方法 equals(Object obj) 需要传入一个 Object 作为参数,并判断该 Object 是否和 Comparator 保持一致。
有时候,我们想让类保持它的原貌,不想主动实现 Comparable 接口,但我们又需要它们之间进行比较,该怎么办呢?
Comparator 就派上用场了,来看一下示例。
1)原封不动的 Cmower 类。
public class Cmower {
private int age;
private String name;
public Cmower(int age, String name) {
this.age = age;
this.name = name;
}
}
(说好原封不动,getter/setter 吃了啊)
Cmower 类有两个字段:age 和 name,意味着该类可以按照 age 或者 name 进行排序。
2)再来看 Comparator 接口的实现类。
public class CmowerComparator implements Comparator<Cmower> {
@Override
public int compare(Cmower o1, Cmower o2) {
return o1.getAge() - o2.getAge();
}
}
按照 age 进行比较。当然也可以再实现一个比较器,按照 name 进行自然排序,示例如下。
public class CmowerNameComparator implements Comparator<Cmower> {
@Override
public int compare(Cmower o1, Cmower o2) {
if (o1.getName().hashCode() < o2.getName().hashCode()) {
return -1;
} else if (o1.getName().hashCode() == o2.getName().hashCode()) {
return 0;
}
return 1;
}
}
3)再来看测试类。
Cmower wanger = new Cmower(19,"沉默王二");
Cmower wangsan = new Cmower(16,"沉默王三");
Cmower wangyi = new Cmower(28,"沉默王一");
List<Cmower> list = new ArrayList<>();
list.add(wanger);
list.add(wangsan);
list.add(wangyi);
list.sort(new CmowerComparator());
for (Cmower c : list) {
System.out.println(c.getName());
}
创建了三个对象,age 不同,name 不同,并把它们加入到了 List 当中。然后使用 List 的 sort() 方法进行排序,来看一下输出的结果。
沉默王三
沉默王二
沉默王一
这意味着沉默王三的年纪比沉默王二小,排在第一位;沉默王一的年纪比沉默王二大,排在第三位。和我们的预期完全符合。
03、到底该用哪一个呢?
通过上面的两个例子可以比较出 Comparable 和 Comparator 两者之间的区别:
- 一个类实现了 Comparable 接口,意味着该类的对象可以直接进行比较(排序),但比较(排序)的方式只有一种,很单一。
- 一个类如果想要保持原样,又需要进行不同方式的比较(排序),就可以定制比较器(实现 Comparator 接口)。
- Comparable 接口在
java.lang包下,而Comparator接口在java.util包下,算不上是亲兄弟,但可以称得上是表(堂)兄弟。
举个不恰当的例子。我想从洛阳出发去北京看长城,体验一下好汉的感觉,要么坐飞机,要么坐高铁;但如果是孙悟空的话,翻个筋斗就到了。我和孙悟空之间有什么区别呢?孙悟空自己实现了 Comparable 接口(他那年代也没有飞机和高铁,没得选),而我可以借助 Comparator 接口(现代化的交通工具)。
总而言之,如果对象的排序需要基于自然顺序,请选择 Comparable,如果需要按照对象的不同属性进行排序,请选择 Comparator。
04、鸣谢
好了,各位读者朋友们,以上就是本文的全部内容了。能看到这里的都是最胖的程序员(不,最棒),升职加薪就是你了
来吧,一文彻底搞懂Java中的Comparable和Comparator的更多相关文章
- 一文彻底搞懂Java中的环境变量
一文搞懂Java环境变量 记得刚接触Java,第一件事就是配环境变量,作为一个初学者,只知道环境变量怎样配,在加上各种IDE使我们能方便的开发,而忽略了其本质的东西,只知其然不知其所以然,随着不断的深 ...
- 来吧,一文彻底搞懂Java中最特殊的存在——null
没事的时候,我并不喜欢逛 P 站,而喜欢逛 programcreek 这些技术型网站,于是那天晚上,在夜深人静的时候,我就发现了一个专注基础但不容忽视的主题.比如说:Java 中的 null 到底是什 ...
- 轻松搞懂Java中的自旋锁
前言 在之前的文章<一文彻底搞懂面试中常问的各种“锁”>中介绍了Java中的各种“锁”,可能对于不是很了解这些概念的同学来说会觉得有点绕,所以我决定拆分出来,逐步详细的介绍一下这些锁的来龙 ...
- 一文搞懂--Java中重写equals方法为什么要重写hashcode方法?
Java中重写equals方法为什么要重写hashcode方法? 直接看下面的例子: 首先我们只重写equals()方法 public class Test { public static void ...
- 一文搞懂 Java 中的枚举,写得非常好!
知识点 概念 enum的全称为 enumeration, 是 JDK 1.5 中引入的新特性. 在Java中,被 enum关键字修饰的类型就是枚举类型.形式如下: enum Color { RED, ...
- 一篇文章让你搞懂Java中的静态代理和动态代理
什么是代理模式 代理模式是常用的java设计模式,在Java中我们通常会通过new一个对象再调用其对应的方法来访问我们需要的服务.代理模式则是通过创建代理类(proxy)的方式间接地来访问我们需要的服 ...
- java 中的 Comparable 和 Comparator 与 Iterable 和 Iterator
Comparable 和 Comparator Comparable 和 Comparator 是两个关系不大的类,其分别侧重于不同的方面. 其中,接口 Comparable<T> 强行对 ...
- 【软件构造】(转)Java中的comparable和comparator
为了方便阅读和复习,转载至此,原地址:温布利往事的博客 阅读目录 一.Comparable简介 二.Comparator简介 三.Comparable和Comparator区别比较 回到顶部 一.Co ...
- 彻底搞懂Java中equals和==的区别
java当中的数据类型和“==”的含义: 1.基本数据类型(也称原始数据类型) :byte,short,char,int,long,float,double,boolean.他们之间的比较,应用双等号 ...
随机推荐
- day1_python之字符串的常用操作
python字符串操作常用操作,如字符串的替换.删除.截取.复制.连接.比较.查找.分割等,需要的朋友可以参考下. 1.去除空格 str.strip():删除字符串两边的指定字符,括号的写入指定字符, ...
- 深入Java线程管理(二):线程的生命周期
Java线程的生命周期 一个线程的产生是从我们调用了start方法开始进入Runnable状态,即可以被调度运行状态,并没有真正开始运行,调度器可以将CPU分配给它,使线程进入Running状态,真正 ...
- SQL,范式,事务
数据库范式: 构造数据库必须遵循一定的规则.在关系数据库中,这种规则就是范式. 范式是符合某一种级别的关系模式的集合.数据库中的关系必须满足一定的要求,即满足不同的范式. 满足最低要求的范式是第一范式 ...
- Vue 路由的嵌套使用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- java操作数组的工具类-Arrays
static int binarySearch(type[] a, type key) 使用二分搜索法来搜索key元素在数组中的索引:若a数组不包括key,返回负数.(该方法必须已按升序排列后调用). ...
- Git篇
安装之后第一步 安装 Git 之后,你要做的第一件事情就是去配置你的名字和邮箱,因为每一次提交都需要这些信息: git config --global user.name "bukas&qu ...
- P1003 电影票价
题目描述 已知一位小朋友的电影票价是10元,请问 \(n\) 位小朋友的总票价是多少? 输入格式 输入一个整数 \(n(1 \le n \le 1000)\) , 用于表示小朋友的数量. 输出格式 输 ...
- win10 uwp 发布旁加载自动更新
在很多企业使用的程序都是不能通过微软商店发布,原因很多,其中我之前的团队开发了很久的应用,结果发现没有用户能从微软应用商店下载所以我对应用商店没有好感.但是作为一个微软粉丝,怎么能不支持 UWP 开发 ...
- ORACLE禁用和启用外键
禁用外键 select 'alter table '|| t.table_name||' disable constraint '||t.constraint_name||';' from user_ ...
- 云栖深度干货 | 打造“云边一体化”,时序时空数据库TSDB技术原理深度解密
本文选自云栖大会下一代云数据库分析专场讲师自修的演讲——<TSDB云边一体化时序时空数据库技术揭秘> 自修 —— 阿里云智能数据库产品事业部高级专家 认识TSDB 第一代时序时 ...