来吧,一文彻底搞懂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.他们之间的比较,应用双等号 ...
随机推荐
- python unittest 框架添加测试用例及运行
找出要测试的testcase,并加入到Testsuite,运行Testsuite并把结果给TestResult1.创建TestSuite实例对象suite = unittest.TestSuite() ...
- H3C 以太网集线器
- H3C 局域网与OSI参考模型
- Lua环境搭建之使用EditPlus搭建Lua开发环境
luatools正则表达式extension工具encoding 一.语法高亮 打开 EditPlus,Tools 工具-->Preferences首选项==>setting & ...
- [Ramda] Handle Errors in Ramda Pipelines with tryCatch
Handling your logic with composable functions makes your code declarative, leading to code that's ea ...
- HDU 5912 Fraction(模拟)
Problem Description Mr. Frog recently studied how to add two fractions up, and he came up with an ev ...
- SpringBoot: 浅谈文件上传和访问的坑 (MultiPartFile)
本次的项目环境为 SpringBoot 2.0.4, JDK8.0. 服务器环境为CentOS7.0, Nginx的忘了版本. 前言 SpringBoot使用MultiPartFile接收来自表单的f ...
- JS的防抖与节流学习笔记
防抖(debounce):当持续触发事件时,在一定的时间段内,只有最后一次触发的事件才会执行. 例: function debounce(fn, wait) { var timer = null; r ...
- linux内核指针和错误值
很多内部内核函数返回一个指针值给调用者. 许多这些函数也可能失败. 大部分情况, 失 败由返回一个 NULL 指针值来指示. 这个技术是能用的, 但是它不能通知问题的确切特性. 一些接口确实需要返回一 ...
- video视频标签一些设置,包括封面、播放结束后的封面、视频占满屏幕的方式、视频播放暂停、展示控制栏、触发全屏播放事件
video视频标签一些设置,包括封面.播放结束后的封面.视频占满屏幕的方式.视频链接.视频播放暂停.展示控制栏.触发全屏播放事件 <video id="video" auto ...