一、使用情景

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的更多相关文章

  1. Java中Comparable和Comparator接口区别分析

    Java中Comparable和Comparator接口区别分析 来源:码农网 | 时间:2015-03-16 10:25:20 | 阅读数:8902 [导读] 本文要来详细分析一下Java中Comp ...

  2. Java 中 Comparable 和 Comparator 比较

    Java 中 Comparable 和 Comparator 比较 目录: Comparable Comparator Comparable 和 Comparator比较 第二个例子 之 Compar ...

  3. java比较器Comparable接口和Comaprator接口

    Comparable故名思意是比较,意思就是做比较的,然后进行排序. 1.什么是comparable接口 此接口强行对实现它的每个类的对象进行整体排序.此排序被称为该类的自然排序 ,类的 compar ...

  4. Java 中 Comparable 和 Comparator 比较(转)

    转自http://www.cnblogs.com/skywang12345/p/3324788.html 本文,先介绍Comparable 和Comparator两个接口,以及它们的差异:接着,通过示 ...

  5. java中Comparable和Comparator两种比较器的区别

    Comparable和Comparator接口都是为了对类进行比较,众所周知,诸如Integer,double等基本数据类型,java可以对他们进行比较,而对于类的比较,需要人工定义比较用到的字段比较 ...

  6. Java的比较器Comparable与Comparator

    在Java中有两个比较器:Comparable.Comparator 对于Integer.Double等等类型,可以直接对他们进行比较,因为已经实现了比较的方式,然而在平时常常会面临需要对集合进行排序 ...

  7. Java中Comparable和Comparator区别小结

    一.Comparable简介 Comparable是排序接口.若一个类实现了Comparable接口,就意味着该类支持排序.实现了Comparable接口的类的对象的列表或数组可以通过Collecti ...

  8. 比较器comparable与comparator的使用

    在Java学习和使用里,工具类与算法类(collections和Arrays)也是我们使用比较多的,在它们里面就包含了comparable与comparator这两种比较器. 一.比较器的分类与概念 ...

  9. Java中Comparable和Comparator你知多少?

    前言: 我喜欢这种遨游在Java的世界里,精心研究学习新鲜事物的感觉,即便再小再细再微不足道的东西,也让我乐此不疲,同时我也更愿意将我所会的东西分享出来供大家学习以及方便自己日后回顾.好了,闲话不多说 ...

随机推荐

  1. python格式转换的记录

    Python的格式转换太难了. 与其说是难,具体来说应该是"每次都会忘记该怎么处理".所以于此记录,总的来说是编码+格式转换的记录. 本文记录环境:python3.6 经常见到的格 ...

  2. Preliminaries for Benelux Algorithm Programming Contest 2019

    A. Architecture 如果行最大值中的最大值和列最大值中的最大值不同的话,那么一定会产生矛盾,可以手模一个样例看看. 当满足行列最大值相同条件的时候,就可以判定了. 因为其余的地方一定可以构 ...

  3. Luogu4168 蒲公英 (分块)

    题目传送门 题意 长度为n的序列,有m次询问,每次询问求\([l,r]\) 间的众数,如果有多个,输出最小的那个 \(n\le 4\times 10^4,m\le 5\times 10^5,a_i\l ...

  4. ABP设置管理模块: Abp.SettingUi

    开源地址: https://github.com/EasyAbp/Abp.SettingUi 一直想宣传一下SettingUi, 因为 懒 工作比较忙, 所以才拖到今天. 关于ABP就不需要我再多废口 ...

  5. C- c常见问题分析

    一.遇到undefined symbol怎么办: (1)首先解析未定义符号是什么:[利用c++filt命令] c++filt _ZN4Json5ValueixERKNSt7__cxx1112basic ...

  6. Ansible主机清单Inventory文件hosts

    Ansible主机清单Inventory文件hosts 发表于 2017-05-14 | 分类于 运维相关 , Ansible | | 阅读次数 4638 | 字数统计 1,442 | 阅读时长预计 ...

  7. Python-collections模块之defaultdict

    defaultdict defaultdict 是 dict 类型的子类,正如其名,初始化时,可以给key指定默认值,什么意思呢?直接看代码.如果是普通的dict对象,访问一个不存在的key时,会报错 ...

  8. 【非原创】LightOj 1248 - Dice (III)【几何分布+期望】

    学习博客:戳这里 题意:有一个 n 面的骰子,问至少看到所有的面一次的所需 掷骰子 的 次数的期望: 第一个面第一次出现的概率是p1 n/n; 第二个面第一次出现的概率是p2 (n-1)/n; 第三个 ...

  9. js map & Number

    js map & Number const regionIds = `1,2,3`; // "1,2,3" regionIds.split(',').map(Number) ...

  10. Nmap & ncat

    Nmap & ncat https://github.com/udacity/course-ud303 https://nmap.org/dist/nmap-7.30-setup.exe Yo ...