很多同学搞不清楚Comparable和Comparator这两个接口,单看这两个单词,一个是形容词一个是名词,但是可以看出来都和比较有关,我个人把实现了Comparable接口的某个类理解成这个类具备了比较能力,而把实现了Comparator的类称为比较器类,那么他们分别该怎么用呢?

目录

  • Comparable(比较能力)
    • PriorityQueue队列
  • Comparator(比较器)
  • 小结

Comparable(比较能力)

PriorityQueue队列

在正式介绍他们俩之前,先给大家介绍一下Java中的优先级队列PriorityQueue,这是一个实现了Queue接口的类,它的功能是add()进入一个个同类型对象,然后它会在内部进行操作,保证每次头删的时候都是队列中的最小的元素。既然要给出队列中的最小值,那么PriorityQueue在每次插入之后都会对其内部元素进行排序,才能保证队首是整个队列的最小值。下面演示一下:

import java.util.PriorityQueue;
import java.util.Queue;public class Main {public static void main(String[] args) {Queue<Integer> queue = new PriorityQueue<>();//入队列queue.add(1);queue.add(999);queue.add(45);queue.add(3);queue.add(66);//看看队首元素System.out.println("对首元素" + queue.element());//出队列queue.remove();//看看对首元素、System.out.println("对首元素" + queue.element());//出队列queue.remove();//看看对首元素、System.out.println("对首元素" + queue.element());//出队列queue.remove();//看看对首元素、System.out.println("对首元素" + queue.element());//出队列queue.remove();//看看对首元素、System.out.println("对首元素" + queue.element());}
}

运行结果:

可以看到每次进行出队列操作后队首元素都是当前队列的最小值,而且这并不是我们插入时的顺序。所以现在可以确定的是每次出队列后PriorityQueue会选出队列中剩余元素中的最小值放在队首,可问题现在PriorityQueue是根据什么来找到的最小值呢?
大家可能会有疑问:1就是最小值啊,999就是最大值啊,这不很明显吗?
可是要知道的是java会对这些基本int类型作自动封装,队列中实际是Integer类的对象,所以问题就是PriorityQueue是怎么比较一个个Integer对象的?
我们点开Java中的Integer类看看:

从图中可以清楚的看到Integer类实现了Comparable接口,好了,说到这里我们来做个简单的总结,PriorityQueue可以将插入的所有元素中的最小值放在队首,怎么判断出哪个元素最小,对中元素实现了Comparable接口才能判断出哪个元素小那个元素大。
要是不实现Comparable接口怎么办呢?
我们来创建一个Student类放到PriorityQueue中看看。

//Student类
public class Student {public String name;public int grade;public int totalScore;public Student(String name, int totalScore){this.name = name;this.totalScore = totalScore;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", totalScore=" + totalScore +'}';}
}

实例化几个student对象,然后试着把他们放到PriorityQueue中看看。

import java.util.PriorityQueue;
import java.util.Queue;public class Main {public static void main(String[] args) {Queue<Student> queue = new PriorityQueue<>();Student a = new Student("张三", 555);Student b = new Student("李四", 378);Student c = new Student("王五", 456);Student d = new Student("魏六", 555);queue.add(a);queue.add(b);queue.add(c);queue.add(d);System.out.println(queue.remove());}
}

报错了:

可以看到在16行出的错:

从图中可以看到出错行16行是在执行b对象也就是第二个对象的插入时出了问题,为什么在插第一个对象的时候不报错呢?回想一下,PriorityQueue会把队列中的最小的元素放在队首,插入第一个对象时全队列只有一个元素所以不需要找最小对象,插第二个对象时队列中有两个元素了需要选两个中较小的一个的时候就出错了,因为我们Student类没有实现Comparable接口,所以PriorityQueue不能比较对象之间谁大谁小,所以在插入的时候报错了。那我们来实现Comparable接口:

public class Student implements Comparable<Student>{public String name;public int grade;public int totalScore;public Student(String name, int totalScore){this.name = name;this.totalScore = totalScore;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", totalScore=" + totalScore +'}';}@Overridepublic int compareTo(Student o) {return 0;}
}

再来执行上面的插入操作:

public class Main {public static void main(String[] args) {Queue<Student> queue = new PriorityQueue<>();Student a = new Student("张三", 555);Student b = new Student("李四", 378);Student c = new Student("王五", 456);Student d = new Student("魏六", 555);queue.add(a);queue.add(b);queue.add(c);queue.add(d);//头删queue.remove();}
}

可以看到因为我们的Student类实现了Comparable接口插入而插入成功了。并且在做出队列操作时也成功删除了。
我们再来捋一捋:因为我们的Student类实现了Comparable接口才能成功的入PriorityQueue队列,可是这里又有一个问题就是PriorityQueue是怎么知道我们插入的哪个元素是最小的?

这是我们Student类实现的Comparable中唯一的一个方法,PriorityQueue是根据这个方法的返回值比较元素大小的。它会两两对队列内的元素进行比较,谁大谁小是根据这个compareTo方法的返回值决定,比如PriorityQueue开始比较时先从例子中的a对象开始,那么它会再依次向a的compareTo()方法中传入b,c,d对象,这样比下来就知道了a和其他三个对象谁大谁小 ,我们要自己重写这个方法来规定是依据this的什么属性和传入对象的什么属性作比较的。
拿Student类来说它的属性有姓名,年级,总成绩三个,我们可以根据总成绩totalScore来做比较依据重写compareTo()方法。成绩高的的Student对象大,成绩低的对象小,这里比较绕,大家还是要明确我们Student类虽然实现了Comparable接口有了比较能力,能插入PriorityQueue,但是想让程序知道哪个对象大哪个对象小全是根据compareTo()方法的返回值看的。
Java默认的是compareTo()返回值为负则表示传入的o对象大,返回0表示一样大,正数表示this对象大。
我们重写Student类的compareTo()方法:

public class Student implements Comparable<Student>{public String name;public int grade;public int totalScore;public Student(String name, int totalScore){this.name = name;this.totalScore = totalScore;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", totalScore=" + totalScore +'}';}@Overridepublic int compareTo(Student o) {return this.totalScore - o.totalScore;}
}

当返回值为负数时表示this.totalScore < o.totalScore,也就是this对象比o对象小。
当返回值为0时表示this.totalScore = o.totalScore,也就是this对象和o对象一样大。
当返回值为正数数时表示this.totalScore > o.totalScore,也就是this对象比o对象大。

import java.util.PriorityQueue;
import java.util.Queue;public class Main {public static void main(String[] args) {Queue<Student> queue = new PriorityQueue<>();Student a = new Student("张三", 555);Student b = new Student("李四", 378);Student c = new Student("王五", 456);Student d = new Student("魏六", 555);queue.add(a);queue.add(b);queue.add(c);queue.add(d);//看看头元素,因为我们是根据总成绩// totalScore来比较大小的,// 那么成绩小的会在队首System.out.println("对首元素" + queue.element());}
}


说到这里大家应该对Comparable的作用有所了解了,实现了它的类就有了比较能力,但是你想根据什么比较两个对象大小还得看你怎么重写compareTo()方法。如果还是迷的话请多卡看一看上面的叙述。

Comparator(比较器)

比较能力是一个类自己具备的,相应的比较器Comparator是要自己建造的,我们要为需要比较的类量身打造一个实现Comparator接口的比较器类,下面创建一个专为Student类量身打造的比较器:
我们先让Student类丧失比较能力也就是不实现Comparable接口,不重写compareTo()方法。

public class Student {public String name;public int grade;public int totalScore;public Student(String name, int totalScore){this.name = name;this.totalScore = totalScore;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", totalScore=" + totalScore +'}';}
}

Student类的比较器类:

import java.util.Comparator;public class Mycomparator implements Comparator<Student> {@Overridepublic int compare(Student o1, Student o2) {//因为比较器和Student自己实现Comparable接口不一样// 比较器属于第三方,所以在使用时需要传入两个要比较的对象//两个对象的比较思路还是和Comparable一样的,拿总成绩比较//总成绩高的对象较大return o1.totalScore - o2.totalScore;}
}

他是这样用的:

import java.util.PriorityQueue;
import java.util.Queue;public class Main {public static void main(String[] args) {Mycomparator myComparator = new Mycomparator();Queue<Student> queue = new PriorityQueue<>(myComparator);Student a = new Student("张三", 555);Student b = new Student("李四", 378);Student c = new Student("王五", 456);Student d = new Student("魏六", 555);queue.add(a);queue.add(b);queue.add(c);queue.add(d);//看看头元素,因为我们是根据总成绩// totalScore来比较大小的,// 那么成绩小的会在队首System.out.println("对首元素" + queue.element());}
}

运行结果:


在创建队列的时候就把比较器传进去。

小结

不管是Comparable(比较能力)和Comparator(比较器)都是用于我们实现的类作比较。Comparable是直接实现于我们创建的类,让这个类以后自己天然具备比较能力,Comparator是我们专为某一个类写的一个比较器类,当需要的时候我们得实例化一个比较器然后传入。至于具体是怎么比较那个对象大那个对象小我们就要根据自己的需要来重写方法了,在此提一下Java会根据这个方法的返回值判断两个对象谁大谁小。

对于实现Comparable接口的compareTo()方法来说返回值为正表示传入的对象大,this对象小;返回值为0两个对象一样大;返回值为负,表示传入的对象比this对象大。

对于实现Comparator接口的compare()方法来说返回值为正则传入的第一个对象大于第二个对象,返回值为0表示传入的两个对象一样大;返回值为负表示传入的第一个对象小于第二个对象。

Java中的Comparable和Comparator到底该怎么用看完就全明白了相关推荐

  1. 后端技术:Java中Spring 和 Spring Boot 有哪些区别,看完你就明白了!

    概述 对于 Spring和 SpringBoot到底有什么区别,我听到了很多答案,刚开始迈入学习 SpringBoot的我当时也是一头雾水,随着经验的积累.我慢慢理解了这两个框架到底有什么区别,相信对 ...

  2. 来吧,一文彻底搞懂Java中的Comparable和Comparator

    大家好,我是沉默王二,周末在逛 programcreek 的时候,我发现了一些专注细节但价值连城的主题.比如说:Java 的 Comparable 和 Comparator 是兄弟俩吗?像这类灵魂拷问 ...

  3. 阿里web前端面试题到底有多可怕?看完就全明白了!

    今天给大家找来了阿里巴巴的前端面试题,让大家感受一下 大企业的风度,看看你自己距离阿里巴巴这样的大型互联网工资还有多远?里面包含前端面试知识的方方面面,目前本人已经拿到阿里offer,希望能对后面找工 ...

  4. c++ vector 一部分_为什么现在的手机都采用Type-C接口?它到底好在哪里?看完你就明白了...

    不知道你们有没有发现,现如今的安卓手机几乎都使用Type-C接口.前两年还只是大部分手机采用的Micro USB接口,只有很小一部分使用的是Type-C接口.那到底是什么原因导致它,能在那么快的速度几 ...

  5. 元素凸起效果_被誉为作物“生殖元素”的“硼”到底有多重要?看完你就明白了...

    哈喽,大家好!这里是种地人!今天我们聊聊"硼"! "硼元素"可能很多种植户朋友几乎都没有用过!其实作物生长所需要的大中微量元素一共有16种.硼元素作为农作物生长 ...

  6. 链接h5代码_H5到底是什么?看完你就明白了!

    关于H5相信大家都接触过,就算你没有制作过,你也在自己的朋友圈看到过,那么什么是H5页面呢?其实H5就是指第5代HTML,也指用H5语言制作的数字产品, HTML是超文本标记语言的英文缩写,上网所看到 ...

  7. 摄影师和php那个好学,你和专业摄影师的差距到底在哪里?看完你就明白了

    我能想到最美好的事 是和你们一起走进摄影的奇妙世界 欢迎回到我们的栏目"视界" 打开搜狗搜索APP,查看更多精彩资讯 摄影是对生命中每个1/100秒的品味. --马克·吕布 关于温 ...

  8. java中的NIO和IO到底是什么区别?20个问题告诉你答案

    摘要:NIO即New IO,这个库是在JDK1.4中才引入的.NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多. 本文分享自华为云社区<jav ...

  9. java中的native方法性能到底怎么样?

    前言 java中的native方法性能到底怎么样? 第一次写博客,如果写的不好,望见谅,烦请指出问题,虚心学习 先说结论,native 方法性能不如java方法 一.native方法? 主要是java ...

最新文章

  1. linux中man 1 2 3
  2. 皮一皮:论北方有多冷...
  3. python 文件路径格式化_python 存储为txt文件路径
  4. 【Android-NCNN-Vulkan】ncnn-vulkan load param model 速度慢
  5. 转仁兄:Binary search and its variation
  6. 30岁学python全栈_知乎热帖!戳痛100万程序员:我30岁了,我还能学Python吗?
  7. Apprentissage du français partie 3
  8. Web页面打印及GridView导出到Excel
  9. 在Vue文件中引用模块的相对路径“@“符号表示什么意思?
  10. 搜狐邮箱怎么开启pop3服务器,POP3是什么?怎样开通POP3?
  11. 中国邮递员问题+代码实现(cpp)
  12. 威漫哨兵机器人_漫威:哨兵机器人天下无敌?这几位变种人就不把他们放在眼里...
  13. 关于对ffmpeg中SAR/DAR/PAR的理解
  14. [软考]项目目标VS项目基准
  15. itextpdf5.x实现合同签署盖章预览功能
  16. IEEE ICCSE 2022 Call for Papers (征文公告)
  17. 【不忘初心】Win11_21H2_22000.100_X64_四合一[纯净精简版][2.9G](2021.8.5)
  18. 提问的艺术!(转载)
  19. python大佬的可视化工具-Bokeh
  20. Kubernetes进阶部分学习笔记

热门文章

  1. 4.UiCollection API 详细介绍
  2. Zabbix安装图解教程
  3. 苹果ipa软件包破解笔记
  4. linux多线程编程之互斥锁
  5. 基于jQuery实现自动或点击切换效果
  6. react-组件状态机制(五)
  7. LeetCode--80. 删除排序数组中的重复项Ⅱ(双指针,暴力)
  8. 国家一级计算机考试模拟题2012版,2012年计算机等级考试一级上机Word模拟题2
  9. 如何确定图片名未改变 php,这里未改变的是数据库中默认的数据,比如修改时间?,还有发布用户名?...
  10. 7-27 出租 (20 分)