小白养成记——Java比较器Comparable和Comparator
一、使用情景
1. 调用Arrays.sort()方法或Collections.sort()方法对自定义类的对象排序
以Arrays.sort()为例。假定有如下自定义的Person类
1 public class Person {
2
3 private String name;
4 private Integer age;
5
6 public Person() {}
7
8 public Person(String name, Integer age) {
9 this.name = name;
10 this.age = age;
11 }
12
13 //Getter and Setter
14
15 @Override
16 public String toString() {
17 return "Person{" +
18 "name='" + name + '\'' +
19 ", age=" + age +
20 '}';
21 }
22
23 @Override
24 public boolean equals(Object o) {
25 if (this == o) return true;
26 if (o == null || getClass() != o.getClass()) return false;
27
28 Person person = (Person) o;
29
30 if (!Objects.equals(name, person.name)) return false;
31 return Objects.equals(age, person.age);
32
33 }
34
35 @Override
36 public int hashCode() {
37 int result = name != null ? name.hashCode() : 0;
38 result = 31 * result + (age != null ? age.hashCode() : 0);
39 return result;
40 }
41 }
compare.beans.Person
创建一个一维数组来存放多个Person对象,然后将该数组作为参数调用数组工具类Arrays的静态方法sort(Object[] a),最后遍历
1 @Test
2 public void test3() {
3 Person[] persons = new Person[]{
4 new Person("Mike", 23),
5 new Person("Alice", 19),
6 new Person("Jerry", 17)
7 };
8 Arrays.sort(persons);
9 for (Person person : persons) {
10 System.out.println(person);
11 }
12 }
compare.test.CompareTest
则会出现java.lang.ClassCastException异常,提示Person不能转换为Comparable,这便需要用到比较器。
2. 在TreeSet容器容器中添加自定义类的对象
还是以上文中的Person类为例。创建一个TreeSet容器,将多个Person对象添加其中,查看是否添加成功
1 @Test
2 public void test4() {
3 Set setOfPersons = new TreeSet();
4 setOfPersons.add(new Person("Mike", 23));
5 setOfPersons.add(new Person("Alice", 19));
6 setOfPersons.add(new Person("Jerry", 17));
7 System.out.println("setOfPersons.size() = " + setOfPersons.size());
8 }
compare.test.CompareTest
可以看到还是会出现java.lang.ClassCastException异常,提示Person不能转换为Comparable。
二、使用方式
1. 自然排序——使用java.lang.Comparable<T>接口
在自定义类时可以让其实现这个Comparable接口,重写接口中的int compareTo(T o)方法,这样该类便“具有了比较的功能”。如创建一个实现了Comparable接口的Person类
1 public class Person implements Comparable<Person> {
2
3 private String name;
4 private Integer age;
5
6 public Person() {}
7
8 public Person(String name, Integer age) {
9 this.name = name;
10 this.age = age;
11 }
12
13 public String getName() {
14 return name;
15 }
16
17 public void setName(String name) {
18 this.name = name;
19 }
20
21 public Integer getAge() {
22 return age;
23 }
24
25 public void setAge(Integer age) {
26 this.age = age;
27 }
28
29 @Override
30 public String toString() {
31 return "Person{" +
32 "name='" + name + '\'' +
33 ", age=" + age +
34 '}';
35 }
36
37 @Override
38 public boolean equals(Object o) {
39 if (this == o) return true;
40 if (o == null || getClass() != o.getClass()) return false;
41
42 Person person = (Person) o;
43
44 if (!Objects.equals(name, person.name)) return false;
45 return Objects.equals(age, person.age);
46
47 }
48
49 @Override
50 public int hashCode() {
51 int result = name != null ? name.hashCode() : 0;
52 result = 31 * result + (age != null ? age.hashCode() : 0);
53 return result;
54 }
55
56 /**
57 * 在这里定义比较的方式,如先比较年龄,若年龄相同则再比较姓名
58 * 按照升序排序的规则为:
59 * 若当前对象的指定属性大于传入的待比较对象的指定属性,则返回一个正整数(如1)
60 * 若当前对象的指定属性小于传入的待比较对象的指定属性,则返回一个负整数(如-1)
61 * 若当前对象的指定属性等于传入的待比较对象的指定属性,则返回0
62 * @param anotherPerson 传入的待比较对象
63 * @return 返回一个整数作为比较结果的参考
64 */
65 @Override
66 public int compareTo(Person anotherPerson) {
67
68 int differ = this.getAge() - anotherPerson.getAge();
69 if (differ != 0) {
70 return differ / Math.abs(differ);
71 }
72 return this.getName().compareTo(anotherPerson.getName());
73 }
74 }
compare.beans.Person
这样的Person类便具有了“比较”的功能,在调用sort()方法或添加到TreeSet容器中时便不会再出现异常,无需再更改代码。显然,最值得关注的地方就是compareTo(T o)方法的实现。由于String以及基本数据类型的包装类都已经实现了带泛型的Comparable接口,类的属性一般来说也都是这些类型,所以在写compareTo(T o)方法的方法体时可以直接调用属性的compareTo(T o)方法,省去条件分支语句。
2. 定制排序——使用java.util.Comparator<T>接口
如果需要让Person类的对象在不同情景下使用不同的排序方式,那么通过让Person类实现Comparable接口的方式便显得不具有灵活性了,此时便可以使用Comparator接口。
Comparator接口的使用与Comparable有所不同,它并不是要让自定义的类来实现,而是在需要排序的地方临时创建一个Comparator的实现类,并实现其中的int compare(T o1, T o2)方法,对传入的对象实现排序(比较)。由于这个实现类只是“临时”的,所以使用一个匿名类即可。
数组工具类Arrays的sort()方法是重载的,除了sort(Object[] a)外还有一个sort(T[] a, Comparator<? super T> c),使用后者,传入一个Comparator接口的匿名实现类便可以实现定制排序,如
1 @Test
2 public void test3() {
3 Person[] persons = new Person[]{
4 new Person("Mike", 23),
5 new Person("Alice", 19),
6 new Person("Jerry", 17)
7 };
8 Arrays.sort(persons, new Comparator<Person>() {
9 @Override
10 public int compare(Person person1, Person person2) {
11 int differ = person1.getName().compareTo(person2.getName());
12 if (differ != 0) {
13 return differ;
14 }
15 return person1.getAge().compareTo(person2.getAge());
16 }
17 });
18 for (Person person : persons) {
19 System.out.println(person);
20 }
21 }
compare.test.CompareTest
这样便会按照匿名类里的compare(T o1, T o2)方法指定的方式来进行排序,无论Person类是否实现了Comparable接口。
对TreeSet的处理类似。可以在创建TreeSet容器时调用其含参的构造器,传入一个Comparator接口的匿名实现类,如
1 @Test
2 public void test4() {
3 Set setOfPersons = new TreeSet(new Comparator<Person>() {
4 @Override
5 public int compare(Person person1, Person person2) {
6 int differ = person1.getName().compareTo(person2.getName());
7 if (differ != 0) {
8 return differ;
9 }
10 return person1.getAge().compareTo(person2.getAge());
11 }
12 });
13 setOfPersons.add(new Person("Mike", 23));
14 setOfPersons.add(new Person("Alice", 19));
15 setOfPersons.add(new Person("Jerry", 17));
16 System.out.println("setOfPersons.size() = " + setOfPersons.size());
17 }
compare.test.CompareTest
三、二者的区分
由于这两个接口名以及其中的方法名都含有compare前缀,因此初次接触很容易混淆。二者的区别有如下几点
1)接口Comparable<T>位于java.lang包下,而接口Comparator<T>位于java.util包下。
2)Comparable<T>接口可以让自定义类来实现,从而使该的类具有“顺序性”;而Comparator<T>接口并不是让自定义类来实现的,只需要在需要用到排序的地方临时创建一个指定泛型的实现类,对指定类型的对象进行排序。
3)Comparable<T>接口的compareTo(T o)方法中含有一个形参,自定义类的对象可以调用;而Comparator<T>接口的compare(T o1, T o2)方法中含有两个形参,一般来说不需要手动调用。
4)定制排序优先。
小白养成记——Java比较器Comparable和Comparator的更多相关文章
- Java中Comparable和Comparator接口区别分析
Java中Comparable和Comparator接口区别分析 来源:码农网 | 时间:2015-03-16 10:25:20 | 阅读数:8902 [导读] 本文要来详细分析一下Java中Comp ...
- Java 中 Comparable 和 Comparator 比较
Java 中 Comparable 和 Comparator 比较 目录: Comparable Comparator Comparable 和 Comparator比较 第二个例子 之 Compar ...
- java比较器Comparable接口和Comaprator接口
Comparable故名思意是比较,意思就是做比较的,然后进行排序. 1.什么是comparable接口 此接口强行对实现它的每个类的对象进行整体排序.此排序被称为该类的自然排序 ,类的 compar ...
- Java 中 Comparable 和 Comparator 比较(转)
转自http://www.cnblogs.com/skywang12345/p/3324788.html 本文,先介绍Comparable 和Comparator两个接口,以及它们的差异:接着,通过示 ...
- java中Comparable和Comparator两种比较器的区别
Comparable和Comparator接口都是为了对类进行比较,众所周知,诸如Integer,double等基本数据类型,java可以对他们进行比较,而对于类的比较,需要人工定义比较用到的字段比较 ...
- Java的比较器Comparable与Comparator
在Java中有两个比较器:Comparable.Comparator 对于Integer.Double等等类型,可以直接对他们进行比较,因为已经实现了比较的方式,然而在平时常常会面临需要对集合进行排序 ...
- Java中Comparable和Comparator区别小结
一.Comparable简介 Comparable是排序接口.若一个类实现了Comparable接口,就意味着该类支持排序.实现了Comparable接口的类的对象的列表或数组可以通过Collecti ...
- 比较器comparable与comparator的使用
在Java学习和使用里,工具类与算法类(collections和Arrays)也是我们使用比较多的,在它们里面就包含了comparable与comparator这两种比较器. 一.比较器的分类与概念 ...
- Java中Comparable和Comparator你知多少?
前言: 我喜欢这种遨游在Java的世界里,精心研究学习新鲜事物的感觉,即便再小再细再微不足道的东西,也让我乐此不疲,同时我也更愿意将我所会的东西分享出来供大家学习以及方便自己日后回顾.好了,闲话不多说 ...
随机推荐
- 2019 China Collegiate Programming Contest Qinhuangdao Onsite F. Forest Program(DFS计算图中所有环的长度)
题目链接:https://codeforces.com/gym/102361/problem/F 题意 有 \(n\) 个点和 \(m\) 条边,每条边属于 \(0\) 或 \(1\) 个环,问去掉一 ...
- HDU4366 Successor【dfs序 分块】
HDU4366 Successor 题意: 给出一棵根为\(1\)的树,每个点有两个权值\(x,y\),每次询问一个点的子树中\(x\)比这个点的\(x\)大且\(y\)值最大的那个点 题解: 如果以 ...
- VJ train1 I-彼岸
一道递推题(我这个菜鸡刚开始以为是排列组合) 题目: 突破蝙蝠的包围,yifenfei来到一处悬崖面前,悬崖彼岸就是前进的方向,好在现在的yifenfei已经学过御剑术,可御剑轻松飞过悬崖.现在的问题 ...
- POJ - 1654 利用叉积求三角形面积 去 间接求多边形面积
题意:在一个平面直角坐标系,一个点总是从原点出发,但是每次移动只能移动8个方向的中的一个并且每次移动距离只有1和√2这两种情况,最后一定会回到原点(以字母5结束),请你计算这个点所画出图形的面积 题解 ...
- Codeforces Round #663 (Div. 2) C. Cyclic Permutations (构造,图?)
题意:对于某个序列,若\(1\le i\le n\),\(1\le j\le i\)且\(p_j>p_i\),或者\(1\le i\le n\),\(i<j \le n\)且\(p_j&g ...
- 活动精彩实录 | 阿里云刘军民(米诺):Cassandra中文社区年度回顾
点击这里观看完整视频 大家好,我是刘军民,我是阿里云数据库的产品经理,目前负责云数据库的产品规划以及相关工作.曾在2019年和多位小伙伴一起发起了中文社区,我希望有更多的小伙伴能加入到社区建设中,这样 ...
- service配置文件
[Unit]Description="itcp Service"After=network.target cs_tcp.service [Service]Type=simpleGu ...
- Python 分析热卖年货,今年春节大家都在送啥?
今年不知道有多少小伙伴留在原地过年,虽然今年过年不能回老家,但这个年也得过,也得买年货,给家人长辈送礼.于是我出于好奇心的想法利用爬虫获取某宝数据,并结合 Python 数据分析和第三方可视化平台来分 ...
- 计算机网络 part1 TCP
一.TCP协议 references:newcoder TCP/IP协议,TCP和UDP的区别及特点 1.四层模型 应用层:载有应用程序,将数据发送给传输层.主要协议有HTTP.SMTP.FTP.DN ...
- Tomcat基本原理
思考 :怎样让Tomcat具备Web服务的功能呢? 在服务端用HTTP来监听,协议不好写,不妨用Java封装好的Socket作为监听. class MyTomcat{ ServerSocket ser ...