一、使用情景

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. Java排序算法(一)冒泡排序

    一.测试类SortTest  import java.util.Arrays; public class SortTest { private static final int L = 20; pub ...

  2. Educational Codeforces Round 20

    Educational Codeforces Round 20  A. Maximal Binary Matrix 直接从上到下从左到右填,注意只剩一个要填的位置的情况 view code //#pr ...

  3. hdu5726 GCD(gcd +二分+rmq)

    Problem Description Give you a sequence of N(N≤100,000) integers : a1,...,an(0<ai≤1000,000,000). ...

  4. Codeforces Round #646 (Div. 2) B. Subsequence Hate(前缀和)

    题目链接:https://codeforces.com/contest/1363/problem/B 题意 可以将 $01$ 串中的 $0$ 变为 $1$.$1$ 变为 $0$,问至少需要变换多少字符 ...

  5. Codeforces Round #613 (Div. 2) B. Just Eat It! (DP)

    题意:有一个长度为\(n\)的序列,找出最大的长度不为\(n\)的子段和,问最大子段和是否小于所有元素和. 题解:最大子段和我们可以直接用dp来找,每次状态转移为:\(dp[i]=max(dp[i-1 ...

  6. 【转】REST风格框架实战:从MVC到前后端分离(附完整Demo)

    版权声明:欢迎转载,注明作者和出处就好!如果不喜欢或文章存在明显的谬误,请留言说明原因再踩哦,谢谢,我也可以知道原因,不断进步! https://blog.csdn.net/justloveyou_/ ...

  7. 实战交付一套dubbo微服务到k8s集群(5)之使用Jenkins进行持续构建交付dubo服务的提供者

    1.登录到jenkins,新建一个项目 2.新建流水线 3.设置保留的天数及份数 4.添加第一个参数:设置项目的名称 5.添加第二个参数:docker镜像名称 6.添加第三个参数:项目所在的git中央 ...

  8. LINUX - vim高效操作

    (一)可以为操作的一行添加下划线 set cursorline

  9. Leetcode(5)-最长回文子串(包含动态规划以及Manacher算法)

    给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为1000. 示例 1: 输入: "babad" 输出: "bab" 注意: &quo ...

  10. pyspark Py4JJavaError: Unsupported class file major version 56

    在jupyter notebook跑上面的代码的时候报错Py4JJavaError: An error occurred while calling z:org.apache.spark.mllib. ...