Java : Comparable 和 Comparator 接口

对象排序#

例如我已经有如下的 Person 类,该类具有 name 和 age 2 个属性,现在我们需要对存放 Person 类的数组或集合进行排序。此时有很多的排序策略,例如对 age 按升序或降序排序,或堆 name 按字典序排序,也可以先按 age 进行排序后对 age 属性相同的对象按 name 的字典序排序。

Copy Highlighter-hljs
class Person{ private String name; private int age; public PersonSortable(String name,int age){ this.name = name; this.age = age; } @Override public String toString() { return name + "-" + age; } }

之前用 C 语言解决问题,需要分别写多个函数,每个函数根据不同的规则运行排序算法。但是由于 Java 的接口技术,因此可以使用 sort() 享受快速排序的快感,这就要求被排序的类实现了对应的接口,常用的支持排序的接口有 Comparable 接口和 Comparator 接口。

Comparable 接口#

compare() 方法#

想要对实例化的对象进行快速排序,前提条件是这个对象是可比较的,例如数字可以按照数值的大小进行排序,而字符可以根据字典序进行排序。而对于一个对象来说,往往这个对象会具有很多属性,这就导致了对对象的排序不能简单地按照大小之类的规则来进行。换言之,个人理解的 Comparable 接口标志了这个类是可比较的,而 compare() 方法界定了这个类的比较规则。当时用 Collections.sort 和 Arrays.sort 进行排序时,就需要参考 compare() 方法定义的规则进行排序。
Comparable 接口指定了类将实现 compare(T o1, T o2) 方法,该方法将定义实例化的对象的比较规则。传入的参数 o1 为要比较的第一个对象,o2 为要比较的第二个对象,根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数。类实现 Comparable 接口后,该对象的列表(和数组)可以通过 Collections.sort 和 Arrays.sort 进行自动排序。

JDK 文档#

Comparable 接口#

compare() 方法#

实例#

例如将上文的 Person 类实现 Comparable 接口,compareTo 方法实现先对 name 属性进行字典序升序排序,如果 name 相同则对 age 进行升序排序。

Copy Highlighter-hljs
import java.util.*; class Person implements Comparable<Person>{ private String name; private int age; public PersonSortable(String name,int age){ this.name = name; this.age = age; } @Override public String toString() { return name + "-" + age; } public int compareTo(PersonSortable obj) { if(this.name.compareTo(obj.name) != 0){ return this.name.compareTo(obj.name); } if(this.age == obj.age){ return 0; } if(this.age > obj.age){ return 1; } else{ return -1; } } }

值的一提的是 String 类也实现了 Comparable 接口,因此可以调用其 compareTo 方法实现按照字典序排序。接下来写个 mian 方法进行测试:

Copy Highlighter-hljs
public static void main(String args[]){ Person array[] = new Person[5]; array[0] = new Person("zhang", 15); array[1] = new Person("zhang", 12); array[2] = new Person("wang", 14); array[3] = new Person("wang", 17); array[4] = new Person("li", 17); Arrays.sort(array); for(int i = 0; i < fre; i++){ System.out.println(array[i].toString()); } System.out.println(Arrays.toString(PersonSortable.class.getInterfaces())); }

Comparator 接口#

compare() 方法#

如果类实现了 Comparable 方法,则该类进行比较的方式就被严格定下来了,但是在实际运用中可能需要让这个类支持多种排序的方式。此时可以引入 Comparator 接口实现这一点,不过 Comparator 接口并非实现在需要被排序的类上,而是用于实现比较器——用于指定比较规则的类。
此时就不难解释为什么 Comparator 接口可以让类的排序支持多种排序方式了,因为可以写多个实现 Comparator 接口的方法的类,让这些不同的类对应不同的排序规则,用于界定排序规则的是 compare() 方法。此时就可以根据实际的需要,传入对应的实现 Comparator 接口的类给 sort 方法进行排序。

JDK 文档#

Comparator 接口#

compare() 方法#

实例#

例如将上文的 Person 类需要支持按 age 属性升序排序和按 name 属性的字典序排序 2 种排序规则,这就需要分别写 2 个实现 Comparator 接口的类来支持。

Copy Highlighter-hljs
//NameComparator 类定义了 Person 对象按照 name 属性排序的规则 class NameComparator implements Comparator<Person>{ public int compare(Person obj1, Person obj2){ return obj1.getName().compareTo(obj2.getName()); } } //AgeComparator 类定义了 Person 对象按照 age 属性排序的规则 class AgeComparator implements Comparator<Person>{ public int compare(Person obj1, Person obj2){ return obj1.getAge() - obj2.getAge(); } }

写个 mian 方法进行测试:

Copy Highlighter-hljs
public static void main(String args[]){ Person array[] = new Person[5]; array[0] = new Person("zhang", 15); array[1] = new Person("zhang", 12); array[2] = new Person("wang", 14); array[3] = new Person("wang", 17); array[4] = new Person("li", 17); //对 name 属性进行排序 Arrays.sort(array,new NameComparator()); //对 sort 方法传入 NameComparator 对象 System.out.println("NameComparator:sort"); for(int i = 0; i < fre; i++){ System.out.println(array[i].toString()); } //对 age 属性进行排序 Arrays.sort(array,new AgeComparator()); //对 sort 方法传入 AgeComparator 对象 System.out.println("AgeComparator:sort"); for(int i = 0; i < fre; i++){ System.out.println(array[i].toString()); } System.out.println(Arrays.toString(NameComparator.class.getInterfaces())); System.out.println(Arrays.toString(AgeComparator.class.getInterfaces())); }

参考资料#

Java第04次实验提纲(面向对象2-继承、多态、抽象类与接口)

posted @   乌漆WhiteMoon  阅读(271)  评论(1编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示
CONTENTS