一、使用情景

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. DEDECMS:解决BMP、jpeg图片或MP4视频无法上传和在后台无法显示

    一.BMP图片无法上传解决方法: 1.修改配置文件: 在include-->dialog的文件夹下, select_images_post.php--> 把 $sparr = Array( ...

  2. Codeforces Round #587 (Div. 3) F Wi-Fi(线段树+dp)

    题意:给定一个字符串s 现在让你用最小的花费 覆盖所有区间 思路:dp[i]表示前i个全覆盖以后的花费 如果是0 我们只能直接加上当前位置的权值 否则 我们可以区间询问一下最小值 然后更新 #incl ...

  3. 2019牛客暑期多校训练营(第七场)F-Energy stones(思维+树状数组)

    >传送门< 题意:有n块能量石,每秒钟会增加Li的能量,但是一旦增长到了Ci它就不会增长了,它初始的能量为Ei. 现在有若干个时刻ti,会选择下标在[Si,Ti]的能量石吸取它们的能量,这 ...

  4. hdu5432Rikka with Array (数位dp+十进制转化为二进制)

    Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, so he ...

  5. 哈希算法解决:HDU1686 && POJ2774 && POJ3261

    HDU1686 题意: 找A串在B串中的出现次数(可重叠),可用KMP做,这里只提供哈希算法做的方法 题解: 先得到A串的hash值,然后在B中枚举起点,长度为lena的子串,检验hash值是否相同就 ...

  6. Codeforces Round #635 C. Linova and Kingdom

    传送门:C. Linova and Kingdom 题意:给你一棵树,要求对k个结点涂色,然后统计每个未涂色结点到根结点的路径上未涂色结点的和,求和最大能为多少 题解:对着样例画几遍,然后贪心发现,最 ...

  7. vi、wc、gzip、bzip2、tar、yum安装、dpek、用户信息操作等命令

    命令模式 输入"dd"即可将这一行删除 按下"p"即可粘贴 插入模式: a:从光标这个位置之后插入 A:在行尾插入 i:从光标之前插入 I:行首插入 o:在光标 ...

  8. haproxy 2.2代理后端https服务

    globalmaxconn 100000chroot /usr/local/haproxystats socket /var/lib/haproxy/haproxy.sock mode 600 lev ...

  9. meterpreter php payload && windows payload 学习

    一 情景 本地kali linux 192.168.1.2 目标 windows NT 服务器192.168.1.4 目的是获取shell 二 过程 首先在linux建立终端 ,msfconsole ...

  10. 关于st表的推导

    #include <bits/stdc++.h> using namespace std; const int maxn=1e6+7; int st[maxn][32]; int a[ma ...