小白养成记——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的世界里,精心研究学习新鲜事物的感觉,即便再小再细再微不足道的东西,也让我乐此不疲,同时我也更愿意将我所会的东西分享出来供大家学习以及方便自己日后回顾.好了,闲话不多说 ...
随机推荐
- Effective Java读书笔记--类和接口
1.使类和成员的可访问性最小化不指定访问级别,就是包私有.protected = 包私有 + 子类一般private不会被访问到,如果实现了Serializable,可能会泄露.反射.final集合或 ...
- 校招有感:计算机专业毕业生如何找工作(Java方向)
这两年毕业生的就业形势,大家都看在眼里.由于我平时本职会到校园去做校招,兼职会做培训,所以也接触到了不少计算机应届毕业生. 我看到的计算机专业毕业生,各种情况的都有.虽然其中有学校的因素,但学校的因素 ...
- 记一次由sql注入到拿下域控的渗透测试实战演练(下)
本次渗透使用工具: mimikatz,PsExec 本次渗透网络拓扑图: 开始渗透: 上一篇文章中我们讲到我们成功渗透了目标内网中web服务器并提取其管理员明文密码,通过明文密码又成功登陆了内网中的另 ...
- A - A Gifts Fixing
t组询问,每次给出数列长度n 以及两个长度为n的数列{ai}和{bi}. 有三种操作:ai−1, bi−1以及ai,bi同时− 1 -1−1. 问最少多少步以后可以让两个数列变成常数数列. ...
- Testing Beta Round (Unrated)
比赛链接:https://codeforces.com/contest/1390 A. 123-sequence 题意 给出一个只含有 $1,2,3$ 的数组,问使所有元素相同至少要替换多少元素. 题 ...
- 【noi 2.6_9275】&【bzoj 3398】Bullcow(DP){Usaco2009 Feb}
题意:一共有N只牡牛(公牛)和牝牛(母牛),每2只牡牛间至少要有K只牝牛才不会斗殴.问无斗殴发生的方案数. 解法:f[i][j]表示一共i只牛,最后一只是j(0为牝牛,1为牡牛)的方案数.f[i][0 ...
- Vue3.0新特性
Vue3.0新特性 Vue3.0的设计目标可以概括为体积更小.速度更快.加强TypeScript支持.加强API设计一致性.提高自身可维护性.开放更多底层功能. 描述 从Vue2到Vue3在一些比较重 ...
- 微服务架构学习Day01-SpringBoot入门
基本概念 SpringBoot的优点: 可以创建独立的Spring应用 SpringBoot嵌入Tomcat,Jetty和Unsertow, 不需要部署war文件 根据需要通过maven获取start ...
- 解决M1 MacBook无法使用pip安装Numpy
问题描述 Python官方已发布支持M1 Apple Silicon的版本,但是在使用pip包管理工具安装一些依赖时发生了错误,这里面就包括在科学计算领域常用的numpy.pandas等.目前可以通过 ...
- HDU 4675 GCD of Sequence(莫比乌斯反演 + 打表注意事项)题解
题意: 给出\(M\)和\(a数组\),询问每一个\(d\in[1,M]\),有多少组数组满足:正好修改\(k\)个\(a\)数组里的数使得和原来不同,并且要\(\leq M\),并且\(gcd(a_ ...