Java comparable 和 comprator

由于其功能性和灵活性,ArrayList是
Java 集合框架中使用最为普遍的集合类之一。ArrayList 是一种 List
实现,它的内部用一个动态数组来存储元素,因此 ArrayList
能够在添加和移除元素的时候进行动态的扩展和缩减。你可能已经使用过
ArrayList,因此我将略过基础部分。如果你对 ArrayList
还不熟悉,你可以参考它的 API
文档,可以很容易理解在 ArrayList
上执行基本的操作。

Java中提供了两种对集合或数组中元素进行排序的方法,一种是实现Comparable接口,另一种是实现Comparator接口。

排序 

在这篇文章中,我将讨论 ArrayList
中一种极其重要的操作,你很有可能需要在企业应用开发中实现它。它就是
ArrayList 元素的排序。

虽然这两种接口看起来差不多,但是在使用方法上有比较大的差别,下面我将开始介绍这两种接口以及它们的一些应用场景。

在java 中我们对ArraryList
中的数据进行排序;通常可以使用Collections.sort()

排序字符串对象的 ArrayList

考虑一个 ArrayList 存储着以字符串形式存在的国名(country
name),为了对这个 ArrayList 进行排序,你需要调用
Collections.sort()方法,传递由国名构成的 ArrayList
对象。这种方法将按照自然顺序(按字母升序)对元素(国名)进行排序。让我们为此来写一段代码。

SortArrayListAscendingDescending.java

package guru.springframework.blog.sortarraylist.ascendingdescending;
 import java.util.ArrayList;
 import java.util.Collections;
 public class SortArrayListAscendingDescending {
 private ArrayList arrayList;
 public SortArrayListAscendingDescending(ArrayList arrayList) {
 this.arrayList = arrayList;
 }
 public ArrayList getArrayList() {
 return this.arrayList;
 }
 public ArrayList sortAscending() {
 Collections.sort(this.arrayList);
 return this.arrayList;
 }
 public ArrayList sortDescending() {
 Collections.sort(this.arrayList, Collections.reverseOrder());
 return this.arrayList;
 }
 }

在上面的类中,我们在构造器中初始化了一个 ArrayList 对象。在
sortAscending()方法中,我们调用了
Collections.sort()方法,并传递这个初始化的
ArrayList对象为参数,返回排序后的 ArrayList。在
sortDescending()方法中,我们调用重载的
Collections.sort()方法让其按照降序对元素排序,这个版本的
Collections.sort()接收ArrayList对象作为第一个参数,一个由
Collections.reverseOrder()方法返回的 Comparator
对象作为第二个参数。我们将会在稍后讲解
Comparator。为了测试排序功能,我们将写一段测试代码。

SortArrayListAscendingDescendingTest.java

package guru.springframework.blog.sortarraylist.ascendingdescending;
 import org.junit.Test;
 import java.util.ArrayList;
 import static org.junit.Assert.*;
 public class SortArrayListAscendingDescendingTest {
 <a href="http://www.jobbole.com/members/madao">@Test</a>
 public void testSortAscendingDescending() throws Exception {
 ArrayList countryList = new ArrayList&lt;&gt;();
 countryList.add("France");
 countryList.add("USA");
 countryList.add("India");
 countryList.add("Spain");
 countryList.add("England");
 SortArrayListAscendingDescending sortArrayList = new SortArrayListAscendingDescending(countryList);
 ArrayList unsortedArrayList = sortArrayList.getArrayList();
 System.out.println("Unsorted ArrayList: " + unsortedArrayList);
 ArrayList sortedArrayListAscending = sortArrayList.sortAscending();
 System.out.println("Sorted ArrayList in Ascending Order : " + sortedArrayListAscending);
 ArrayList sortedArrayListDescending = sortArrayList.sortDescending();
 System.out.println("Sorted ArrayList in Descending Order: " + sortedArrayListDescending);
 }
 }

在上面的测试代码中,我们创建一个 ArrayList 对象,并添加了 5
个字符串对象代表 5 个国家的名字。然后我们调用
getArrayList()、sortAscending()和
sortDescending()方法,并打印这些方法返回的 ArrayList 对象。

输出如下:

------------------------------------------------------- 
T E S T S 
-------------------------------------------------------   
Running guru.springframework.blog.sortarraylist.ascendingdescending.SortArrayListAscendingDescendingTest   
Unsorted ArrayList: [France, USA, India, Spain, England] 
Sorted ArrayList in Ascending Order : [England, France, India, Spain, USA] 
Sorted ArrayList in Descending Order: [USA, Spain, India, France, England]   
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.001 sec - in guru.springframework.blog.sortarraylis

到目前为止,所要排序的 ArrayList 元素都是非常简单的,我们仅仅只是调用
Collections.sort()方法并传递了需要排序的 ArrayList
对象作为参数。但是更多的是你会遇到一些复杂的情景下对 ArrayList
进行排序。

Collections.sort() 方法对 ArrayList 的元素或者任何其他 List
的实现提供的可比较的元素进行排序,这意味着这些元素的类需要实现 java.lang
包中的 Comparable 接口。正如 String
类实现了 Comparable 接口,我们就可以对由国名构成的 ArrayList
排序。有些其他的标准 Java 类实现了 Comparable
接口,包括原始的包装类,例如
Integer、Short、Double、Float、Boolean、BigInteger、BigDecimal、File 和
Date 类都实现了 Comparable 接口。

接口名称 主要函数
Comparable java.lang int compareTo(T o)(比较此对象与指定对象的顺序)
Comparator java.util int compare(T o1,T o2)(比较用来排序的两个参数) ,boolean equals(Object obj)(指示某个其他对象是否“等于”此Comparator)

如果ArrayList 里面的元素是String 对象;这样使用是没有问题的。

使用Comparable排序ArrayList

Comparable 是带有单一 compareTo()方法的接口。一个实现了 Comparable
接口的类对象可以与其它同类型的对象进行比较,实现 Comparable
接口的类需要重写
compareTo()方法,这个方法接收一个同类型的对象,并实现这个对象和传递给方法的另一个对象比较的逻辑。compareTo()方法返回Int类型的比较结果,分别代表下面的含义:

  • 正值表示当前对象比传递给 comPareTO()的对象大
  • 负值表示当前对象比传递给 comPareTO()的对象小
  • 零表示两个对象相等

让我们来举一个例子,JobCandidate 类的对象保存在 ArrayList
中并准备对其进行排序。JobCandidate
类有三个成员变量:字符串类型的姓名和性别、整型的年龄。我们想要对保存在
ArrayList 中的 JobCandidate 对象按照年龄进行排序。因此我们要让
JobCandidate 类实现 Comparable 接口并重写 compareTo()方法。

JobCandidate类的代码如下:

JobCandidate.java

package guru.springframework.blog.sortarraylist.comparable;
 public class JobCandidate implements Comparable {
 private String name;
 private String gender;
 private int age;
 public JobCandidate(String name, String gender, int age) {
 this.name = name;
 this.gender = gender;
 this.age = age;
 }
 public String getName() {
 return name;
 }
 public String getGender() {
 return gender;
 }
 public int getAge() {
 return age;
 }
 @Override
 public int compareTo(JobCandidate candidate) {
 return (this.getAge() < candidate.getAge() ? -1 :
 (this.getAge() == candidate.getAge() ? 0 : 1));
 }
 @Override
 public String toString() {
 return " Name: " + this.name + ", Gender: " + this.gender + ", age:" + this.age;
 }
 }

在上面 JobCandidate 类被重写的
compareTo()方法中,我们实现了基于年龄的比较逻辑。我见过很多程序员将(this.getAge()
– candidate.getAge())作为返回的比较结果。尽管使用这种 return
语句看上去似乎很吸引人,并且也不会对我们的例子造成影响,我的建议是远离这种语句。想象一下,比较整数值,其中有一个或者两个都是负数的结果。这会导致一些错误,让你的程序行为不定,而且更重要的是,这样的错误是很细微的,尤其是在大型的企业应用中很难检测出来。下面我们将写一个辅助类,为委托方对包含了
JobCandidate 元素的 ArrayList 对象进行排序。

JobCandidateSorter.java

package guru.springframework.blog.sortarraylist.comparable;
import java.util.ArrayList;
 import java.util.Collections;
 public class JobCandidateSorter {
 ArrayList jobCandidate = new ArrayList<>();
 public JobCandidateSorter(ArrayList jobCandidate) {
 this.jobCandidate = jobCandidate;
 }
 public ArrayList getSortedJobCandidateByAge() {
 Collections.sort(jobCandidate);
 return jobCandidate;
 }
 }

在 JobCandidateSorter 类中,我们初始化了一个 ArrayList
对象,委托方将通过构造函数实例化 JobCandidateSorter 。然后我们编写了
getSortedJobCandidateByAge()方法,在这个方法中,我们调用
Collections.sort()并传递已经初始化了的 ArrayList
为参数,最后返回排序后的 ArrayList。

接下来,我们写一个测试类来测试一下我们的代码。

JobCandidateSorterTest.java

package guru.springframework.blog.sortarraylist.comparable;
 import org.junit.Test;
 import java.lang.reflect.Array;
 import java.util.ArrayList;
 import static org.junit.Assert.*;
 public class JobCandidateSorterTest {
 <a href="http://www.jobbole.com/members/madao">@Test</a>
 public void testGetSortedJobCandidateByAge() throws Exception {
 JobCandidate jobCandidate1 = new JobCandidate("Mark Smith", "Male", 26);
 JobCandidate jobCandidate2 = new JobCandidate("Sandy Hunt", "Female", 23);
 JobCandidate jobCandidate3 = new JobCandidate("Betty Clark", "Female", 20);
 JobCandidate jobCandidate4 = new JobCandidate("Andrew Styne", "Male", 24);
 ArrayList jobCandidateList = new ArrayList&lt;&gt;();
 jobCandidateList.add(jobCandidate1);
 jobCandidateList.add(jobCandidate2);
 jobCandidateList.add(jobCandidate3);
 jobCandidateList.add(jobCandidate4);
 JobCandidateSorter jobCandidateSorter = new JobCandidateSorter(jobCandidateList);
 ArrayList sortedJobCandidate = jobCandidateSorter.getSortedJobCandidateByAge();
 System.out.println("-----Sorted JobCandidate by age: Ascending-----");
for (JobCandidate jobCandidate : sortedJobCandidate) {
 System.out.println(jobCandidate);
 }
 }
 }

在上面的测试类中,我们创建了四个 JobCandidate 对象并把它们添加到
ArrayList,然后传递这个 ArrayList 到构造函数来实例化 JobCandidateSorter
类。最后,我们调用 JobCandidateSorter 类的
getSortedJobCandidateByAge()方法,并打印这个方法返回的排序后的
ArrayList。测试的输出结果如下:

------------------------------------------------------- 
T E S T S 
------------------------------------------------------- 
Running guru.springframework.blog.sortarraylist.comparable.JobCandidateSorterTest 
-----Sorted JobCandidate by age: Ascending----- 
Name: Betty Clark, Gender: Female, age:20 
Name: Sandy Hunt, Gender: Female, age:23 
Name: Andrew Styne, Gender: Male, age:24 
Name: Mark Smith, Gender: Male, age:26 
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.003 sec 
- in guru.springframework.blog.sortarraylist.comparable.JobCandidateSorterTest

使用 Comparable 对 ArrayList
排序是一种常用的方法。但是你必须知道有某些限制。你想要排序的对象的类必须实现
Comparable 并覆写
compareTo()方法。这基本上意味着你将只能基于一个成员变量来比较对象(我们例子中的年龄字段)。如果要求你按照姓名和年龄来对
JobCandidate 对象进行排序怎么办? Comparable
就不是解决的方法了。另外,比较逻辑是需要进行比较的对象的类的一部分,它消除了比较逻辑可复用性的可能。Java
通过使用在 java.util 包下提供的Comparator接口解决了上述的比较需求。

一、Comparable接口

public interface Comparable<T>

下面这段介绍来自官方文档:

此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的compareTo方法被称为它的自然比较方法。
实现此接口的对象列表(和数组)可以通过Collections.sort(和Arrays.sort)进行自动排序。实现此接口的可以用作有序映射(实现了SortedMap接口的对象)澳门新葡萄京官网首页 ,有序集合(实现了SortedSet接口的对象)中的元素,无需指定比较器。
建议(虽然不是必需的)最好使自然排序与equals一致。
所谓自然排序与equals一致指的是 类A 对于每一个 o1 和 o2 来说,当且仅当
( o1.compareTo( o2 ) )与 o1.equals( o2 )具有相同的 布尔值
时,类A的自然排序才叫做与equals一致。

下面将文档中出现的几个点抽出来单独理解:

  • 自然排序:Comparable接口强行对实现它的类的对象进行整体排序,这样的排序称为该类的自然排序;
  • 自然排序与equals一致:类A 对于每一个 o1 和 o2 来说,当且仅当 (
    o1.compareTo( o2 ) )与 o1.equals( o2 )具有相同的 布尔值
    时,类A的自然排序才叫做与equals一致。

但是如果是我们自己写的对象进行排序;就不能这样使用,大家不妨可以试一下。

使用 Comparator 排序 ArrayList

Comparator 接口与Comparable 接口相似也提供了一个单一的比较方法叫作
compare()。然而,与 Comparable的 compareTo()方法不同的是,这个
compare()接受两个同类型的不同对象进行比较。

我们将用 Comparator 对我们之前使用过的相同 JobCandidate
类对象进行排序。我们将通过实现 Comparatoras 匿名内部类,允许对
JobCandidate 对象按照年龄和姓名进行排序。

下面是使用了 Comparator 的 JobCandidate 类代码

JobCandidate.java

package guru.springframework.blog.sortarraylist.comparator;
 import java.util.Comparator;
 public class JobCandidate {
 private String name;
 private String gender;
 private int age;
 public JobCandidate(String name, String gender, int age) {
 this.name = name;
 this.gender = gender;
 this.age = age;
 }
 public String getName() {
 return name;
 }
 public String getGender() {
 return gender;
 }
 public int getAge() {
 return age;
 }
 public static Comparator ageComparator = new Comparator() {
 @Override
 public int compare(JobCandidate jc1, JobCandidate jc2) {
 return (jc2.getAge() < jc1.getAge() ? -1 :
 (jc2.getAge() == jc1.getAge() ? 0 : 1));
 }
 };
 public static Comparator nameComparator = new Comparator() {
 @Override
 public int compare(JobCandidate jc1, JobCandidate jc2) {
 return (int) (jc1.getName().compareTo(jc2.getName()));
 }
 };
 @Override
 public String toString() {
 return " Name: " + this.name + ", Gender: " + this.gender + ", age:" + this.age;
 }
 }

在上面的类中,从 29 行到 35 行,我们写了一个匿名类并实现了
compare()方法,按照年龄的降序对 JobCandidate
对象进行排序。从37行到42行,我们又写了一个匿名类并实现了 compare()
方法,按照姓名的升序对
JobCandidate进行排序。现在我们写一个类,为委托方对 ArrayList
的元素进行排序。

JobCandidateSorter.java

package guru.springframework.blog.sortarraylist.comparator;
 import java.util.ArrayList;
 import java.util.Collections;
 public class JobCandidateSorter {
 ArrayList jobCandidate = new ArrayList<>();
 public JobCandidateSorter(ArrayList jobCandidate) {
 this.jobCandidate = jobCandidate;
 }
 public ArrayList getSortedJobCandidateByAge() {
 Collections.sort(jobCandidate, JobCandidate.ageComparator);
 return jobCandidate;
 }
 public ArrayList getSortedJobCandidateByName() {
 Collections.sort(jobCandidate, JobCandidate.nameComparator);
 return jobCandidate;
 }
 }

在上面的类中,我们写了
getSortedJobCandidateByAge()方法,在这个方法内部我们调用了
Collections.sort()的重载版本,这个版本传递要被排序的 ArrayList
对象和比较年龄的 Comparator 对象。在
getSortedJobCandidateByName()方法内部,我们又调用了
Collections.sort()的另一个重载版本,这个版本传递要被排序的 ArrayList
对象和比较姓名的 Comparator 对象。

让我们写一个测试类来测试我们的代码。

JobCandidateSorterTest.java

package guru.springframework.blog.sortarraylist.comparator;
 import guru.springframework.blog.sortarraylist.comparator.JobCandidate;
 import guru.springframework.blog.sortarraylist.comparator.JobCandidateSorter;
 import org.junit.Before;
 import org.junit.Test;
 import java.util.ArrayList;
 import static org.junit.Assert.*;
 public class JobCandidateSorterTest {
 JobCandidateSorter jobCandidateSorter;
 @Before
 public void setUp() throws Exception {
 JobCandidate jobCandidate1 = new JobCandidate("Mark Smith", "Male", 26);
 JobCandidate jobCandidate2 = new JobCandidate("Sandy Hunt", "Female", 23);
 JobCandidate jobCandidate3 = new JobCandidate("Betty Clark", "Female", 20);
 JobCandidate jobCandidate4 = new JobCandidate("Andrew Styne", "Male", 24);
 ArrayList jobCandidateList = new ArrayList&lt;&gt;();
 jobCandidateList.add(jobCandidate1);
 jobCandidateList.add(jobCandidate2);
 jobCandidateList.add(jobCandidate3);
 jobCandidateList.add(jobCandidate4);
 jobCandidateSorter = new JobCandidateSorter(jobCandidateList);
 }
 <a href="http://www.jobbole.com/members/madao">@Test</a>
 public void testGetSortedJobCandidateByAge() throws Exception {
 System.out.println("-----Sorted JobCandidate by age: Descending-----");
ArrayList sortedJobCandidate = jobCandidateSorter.getSortedJobCandidateByAge();
 for (JobCandidate jobCandidate : sortedJobCandidate) {
 System.out.println(jobCandidate);
 }
 }
 <a href="http://www.jobbole.com/members/madao">@Test</a>
 public void testGetSortedJobCandidateByName() throws Exception {
 System.out.println("-----Sorted JobCandidate by name: Ascending-----");
ArrayList sortedJobCandidate = jobCandidateSorter.getSortedJobCandidateByName();
 for (JobCandidate jobCandidate : sortedJobCandidate) {
 System.out.println(jobCandidate);
 }
 }
 }

在测试类中我们向 ArrayList 中添加若干 JobCandidate 对象,并使用 Before
注释在测试单元的 setup()方法中创建了一个 JobCandidateSorter
对象。如果你是一个 Junit 新手,可以参考我以前的文章包括 Junit
注释(Junit
单元测试系列)。在
testGetSortedJobCandidateByAge()测试方法中我们调用了
getSortedJobCandidateByAge()方法,并打印了该方法返回的排序后的
ArrayList。在
testGetSortedJobCandidateByName()测试方法中我们调用了getSortedJobCandidateByName()方法并同样打印该方法返回的
ArrayList。测试的输出如下:

-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running guru.springframework.blog.sortarraylist.comparator.JobCandidateSorterTest
-----Sorted JobCandidate by name: Ascending-----
Name: Andrew Styne, Gender: Male, age:24
 Name: Betty Clark, Gender: Female, age:20
 Name: Mark Smith, Gender: Male, age:26
 Name: Sandy Hunt, Gender: Female, age:23
-----Sorted JobCandidate by age: Descending-----
Name: Mark Smith, Gender: Male, age:26
 Name: Andrew Styne, Gender: Male, age:24
 Name: Sandy Hunt, Gender: Female, age:23
 Name: Betty Clark, Gender: Female, age:20
 Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.023 sec
- in guru.springframework.blog.sortarraylist.comparator.JobCandidateSorterTest

方法详细信息:

int compareTo(T o) 比较此对象与指定对象的顺序

比较此对象与指定对象的顺序,如果该对象小于、等于、或大于指定对象,则分别返回负整数、零或正整数。
实现类必须确保对于所有的 x 和 y 都存在 sgn(x.compareTo(y)) ==
-sgn(y.compareTo(x)) 的关系。(这意味着如果 y.compareTo(x)
抛出一个异常,则 x.compareTo(y) 也要抛出一个异常。)

  • 参数: o – 要比较的对象
  • 返回: 负整数、零或正整数,根据此对象是小于、等于还是大于指定对象
  • 抛出: CalssCastException –
    如果指定对象的类型不允许它与此对象进行比较

通过一个小例子来介绍如何使用Comparable接口:
下面是一个普通的Person类,name和age两个属性以及对应的get和set方法。

没有实现Comparable接口的Person类

下面是一个PersonTest测试类以及打印的结果:
我们往一个list当中添加了五个Person对象,然后将此list中的内容打印输出,发现输出的顺序和添加的顺序是一致的。

测试类

打印结果

如果我们此时需要按照Person对象的年龄从小到大输出,该如何实现呢?
这个时候Comparable接口就派上用场了

我们把Person改造一下,让它实现Comparable<T>接口并重写其compareTo方法:

实现了Comparable接口的Person类

然后在测试类中调用 Collections.sort()
方法对list进行排序之后输出结果:

使用了Collections.sortf方法之后的结果

我们可以注意,其实我们在这里显式地指定了比较器:Collection.sort()。
但是对于那些实现了 SortedMap接口 的对象或者是实现了 SortedSet接口
的对象来说,无需指定比较器即可完成我们所需的功能。

使用实现了SortedSet接口的TreeSet无需指定比较器

那我们要如何才能实现自己添加类的排序功能呢?不妨先来看看sort方法的使用说明

总结

在本文中我们看到了 ArrayList 排序的不同方法。一种是使用 Comparable
另一种是使用
Comparator。方法的选择一直是造成程序员们困惑的原因之一。你最应该记住的就是一个
Comparable 对象可以说“我可以自己与另外一个对象比较”而一个 Comparator
对象可以说“我可以比较两个不同的对象”。你不能说一个接口比另一个要好。选择的接口取决于你需要实现的功能。

二、Comparator接口

public interface Comparator<T>

下面这段介绍来自官方文档:

强行对某个对象collection进行整体排序的比较函数。可以将 Comparator
传递给 sort 方法(如 Collections.sort 或
Arrays.sort),从而允许在排序顺序上实现精确控制。还可以使用 Comparator
来控制某些数据结构(如有序 set
或有序映射)的顺序,或者为那些没有自然顺序的对象 collection
提供排序。
当且仅当对于一组元素 S 中的每个 e1 和 e2 而言,c.compare(e1, e2)==0 与
e1.equals(e2) 具有相等的布尔值时,Comparator c 强行对 S
进行的排序才叫做与 equals 一致 的排序。
当使用具有与 equals 不一致的强行排序能力的 Comparator 对有序
set(或有序映射)进行排序时,应该小心谨慎。假定一个带显式 Comparator c
的有序 set(或有序映射)与从 set S
中抽取出来的元素(或键)一起使用。如果 c 强行对 S 进行的排序是与
equals 不一致的,那么有序
set(或有序映射)将是行为“怪异的”。尤其是有序
set(或有序映射)将违背根据 equals 所定义的
set(或映射)的常规协定。
例如,假定使用 Comparator c 将满足 (a.equals(b) && c.compare(a, b) !=
0) 的两个元素 a 和 b 添加到一个空 TreeSet 中,则第二个 add 操作将返回
true(树 set 的大小将会增加),因为从树 set 的角度来看,a 和 b
是不相等的,即使这与 Set.add 方法的规范相反。
注:通常来说,让Comparator也实现 java.io.Serializable
是一个好主意,因为它们在可序列化的数据结构(像 TreeSet
、TreeMap)中可用作排序方法。为了成功地序列化数据结构,Comparator(如果已提供)必须实现Serializable。

public static> void sort(Listlist)

方法详细信息:

int compare(T o1, T o2) 比较用来排序的两个参数

比较用来排序的两个参数。根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数。

boolean equals(Object obj) 指示某个其他对象是否“等于”此Comparator

指示某个其他对象是否“等于”此 Comparator。此方法必须遵守
Object.equals(Object)的常规协定。此外,仅当指定的对象也是一个Comparator,并且强行实施与此
Comparator
相同的排序时,此方法才返回true。因此,comp1.equals(comp2)意味着对于每个对象引用o1和o2而言,都存在sgn(comp1.compare(o1,
o2))==sgn(comp2.compare(o1,
o2))。注意,不重写Object.equals(Object)方法总是安全的。然而,在某些情况下,重写此方法可以允许程序确定两个不同的
Comparator 是否强行实施了相同的排序,从而提高性能。

下面继续使用Person类来说说该如何通过使用Comparator<T>接口来帮助我们实现排序:
Person类使用的还是上面那个没有实现任何接口的Person类。
那么我们该如何对Person类的对象进行排序呢?
****其实只要合理使用Comparator接口就行了,如下图:**

通过实现Comparator接口来对集合进行排序

All elements in the list must implement the Comparable interface.

现在我们可以来回答下面这个问题了:

TreeSet和TreeMap在排序时如何比较元素?Collections工具类中的sort(
)方法如何比较元素?

TreeSet要求存放的对象所属类必需实现Comparable接口,该接口提供了比较元素的
compareTo( ) 方法,当插入元素的时候会回调该方法比较元素的大小。
TreeMap要求存放的键值对映射的键必需实现Comparable接口从而根据键对元素进行排序。
另外Collections工具类中的 sort( ) 方法有两种重载形式:

  • 第一种要求传入的待排序容器中存放的对象比较实现 Comaprable
    接口以实现元素的比较;
  • 第二种不强制的要求容器中的元素必须可以进行比较,但是要求传入的第二个参数,参数是
    Comparator 接口的子类型(需要重写 compare
    方法实现元素的比较),相当于临时定义一个排序规则,通过接口注入比较元素的大小,也就是对回调模式的应用。

附加问题:如果对ArrayList进行排序?
其实我在上面的程序当中已经演示得很清楚了。ArrayList不像TreeMap和TreeSet,可以在元素插入的过程中进行排序。我们可以在元素全部插入完毕时候通过调用Collections工具类的
sort( ) 方法对里面的元素进行排序。

Furthermore, all elements in the list must be mutually comparable (that
is, e1.compareTo(e2) must not throw a ClassCastException for any
elements e1 and e2 in the list).a negative integer if this instance is
less than another;

a positive integer if this instance is greater than another;;

0 if this instance has the same order as another.;


Comparable

如果自己添加的类需要支持排序,我们需要实现Comparable

假如我们需要排序的对象是这样定义的;我们需要根据对象人的姓名进行排序

class Person{

String name;

}那么我们可以实现Comparable 接口来对我们自己添加的类进行比较

class Person implements Comparable{

String Name;

public int compareTo(Person p){

return name.compareTo(p.getName);

}

public String getName(){

return name;

}

}实现了Comparable的对象,我们就可以调用Collections.sort来对我们的数据进行排序了。


Comparator

当然如果我们自己定义的对象只需要通过一种方式比较排序;那么刚才通过类实现Comparable的方法已经满足要求了;

但是如果,我们需要根据不同的属性进行排序,刚才的方法就不行了;

我们再来看看sort的另一个重载函数

public staticvoid sort(Listlist,

Comparator c)

Sorts the specified list according to the order induced by the specified
comparator.

All elements in the list must be mutually comparable using the specified
comparator (that is, c.compare(e1, e2) must not throw a
ClassCastException for any elements e1 and e2 in the
list).意思就是我们可以通过comparator来达到目的

//我们需要根据人的年龄 和 人的身高排序class Person{String name;int
age;int height}//创建并实现按年龄排序的 comparator的内部类class
AgeCompare implements Comparator{  public int compare(Person p1,Person
p2){      return p1.age-p2.age; 
}}//创建并实现按身高排序的Comparator内部类class HeightCompare implements
Comparator{

public int compare(Person p1,Person p2){

return p1.height-p2.height;

}

}


实例 

在gallery
里面,我们需要把图片或者视频按时间分类的时候;我们通常都会对所有对象先进行排序处理

//排序的类

class SmallItem {  

  Path path;  

  long dateInMs;    

double lat, lng;  

  int mediaType;}/

/按时间排序,实现comparatorprivate 

static class DateComparator implements Comparator{        

@Override        public int compare(SmallItem item1, SmallItem item2) { 
          

return -Utils.compare(item1.dateInMs, item2.dateInMs);        }   
}//调用sort

private static final ComparatorsDateComparator =new DateComparator();

Collections.sort(items, sDateComparator);


参考

发表评论

电子邮件地址不会被公开。 必填项已用*标注