对比Java中的Comparable排序接口和Comparator比较器接口
comparable
comparable 是排序接口。
若一个类实现了comparable接口,就意味着“该类支持排序”。 即然实现comparable接口的类支持排序,假设现在存在“实现comparable接口的类的对象的list列表(或数组)”,则该list列表(或数组)可以通过 collections.sort(或 arrays.sort)进行排序。
此外,“实现comparable接口的类的对象”可以用作“有序映射(如treemap)”中的键或“有序集合(treeset)”中的元素,而不需要指定比较器。
comparable 接口仅仅只包括一个函数,它的定义如下:
package java.lang; import java.util.*; public interface comparable<t> { public int compareto(t o); }
说明: 假设我们通过 x.compareto(y) 来“比较x和y的大小”。若返回“负数”,意味着“x比y小”;返回“零”,意味着“x等于y”;返回“正数”,意味着“x大于y”。
comparable 接口已经泛型化了,所以实现 comparable 的对象声明它可以与什么类型进行比较。(通常,这是对象本身的类型,但是有时也可能是父类。)
public interface comparable { public boolean compareto(t other); }
所以 comparable 接口包含一个类型参数 t,该参数是一个实现 comparable 的类可以与之比较的对象的类型。这意味着如果定义一个实现 comparable 的类,比如 string,就必须不仅声明类支持比较,还要声明它可与什么比较(通常是与它本身比较):
public class string implements comparable { ... }
现在来考虑一个二元 max() 方法的实现。您想要接受两个相同类型的参数,二者都是 comparable,并且相互之间是 comparable。幸运的是,如果使用泛型方法和有限制类型参数的话,这相当直观:
public static > t max(t t1, t t2) { if (t1.compareto(t2) > 0) return t1; else return t2; }
在本例中,您定义了一个泛型方法,在类型 t 上泛型化,您约束该类型扩展(实现) comparable。两个参数都必须是 t 类型,这表示它们是相同类型,支持比较,并且相互可比较。容易!
更好的是,编译器将使用类型推理来确定当调用 max() 时 t 的值表示什么意思。所以根本不用指定 t,下面的调用就能工作:
string s = max("moo", "bark");
编译器将计算出 t 的预定值是 string,因此它将进行编译和类型检查。但是如果您试图用不实现 comparable 的 类 x 的参数调用max(),那么编译器将不允许这样做。
comparator
comparator 是比较器接口。
我们若需要控制某个类的次序,而该类本身不支持排序(即没有实现comparable接口);那么,我们可以建立一个“该类的比较器”来进行排序。这个“比较器”只需要实现comparator接口即可。
也就是说,我们可以通过“实现comparator类来新建一个比较器”,然后通过该比较器对类进行排序。
comparator 接口仅仅只包括两个个函数,它的定义如下:
package java.util; public interface comparator<t> { int compare(t o1, t o2); boolean equals(object obj); }
说明:
1.若一个类要实现comparator接口:它一定要实现compareto(t o1, t o2) 函数,但可以不实现 equals(object obj) 函数。
为什么可以不实现 equals(object obj) 函数呢? 因为任何类,默认都是已经实现了equals(object obj)的。 java中的一切类都是继承于java.lang.object,在object.java中实现了equals(object obj)函数;所以,其它所有的类也相当于都实现了该函数。
2.int compare(t o1, t o2) 是“比较o1和o2的大小”。返回“负数”,意味着“o1比o2小”;返回“零”,意味着“o1等于o2”;返回“正数”,意味着“o1大于o2”。
comparator 和 comparable 比较
comparable是排序接口;若一个类实现了comparable接口,就意味着“该类支持排序”。
而comparator是比较器;我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。
我们不难发现:comparable相当于“内部比较器”,而comparator相当于“外部比较器”。
我们通过一个测试程序来对这两个接口进行说明。源码如下:
import java.util.*; import java.lang.comparable; /** * @desc "comparator"和“comparable”的比较程序。 * (01) "comparable" * 它是一个排序接口,只包含一个函数compareto()。 * 一个类实现了comparable接口,就意味着“该类本身支持排序”,它可以直接通过arrays.sort() 或 collections.sort()进行排序。 * (02) "comparator" * 它是一个比较器接口,包括两个函数:compare() 和 equals()。 * 一个类实现了comparator接口,那么它就是一个“比较器”。其它的类,可以根据该比较器去排序。 * * 综上所述:comparable是内部比较器,而comparator是外部比较器。 * 一个类本身实现了comparable比较器,就意味着它本身支持排序;若它本身没实现comparable,也可以通过外部比较器comparator进行排序。 */ public class comparecomparatorandcomparabletest{ public static void main(string[] args) { // 新建arraylist(动态数组) arraylist<person> list = new arraylist<person>(); // 添加对象到arraylist中 list.add(new person("ccc", 20)); list.add(new person("aaa", 30)); list.add(new person("bbb", 10)); list.add(new person("ddd", 40)); // 打印list的原始序列 system.out.printf("original sort, list:%s\n", list); // 对list进行排序 // 这里会根据“person实现的comparable<string>接口”进行排序,即会根据“name”进行排序 collections.sort(list); system.out.printf("name sort, list:%s\n", list); // 通过“比较器(ascagecomparator)”,对list进行排序 // ascagecomparator的排序方式是:根据“age”的升序排序 collections.sort(list, new ascagecomparator()); system.out.printf("asc(age) sort, list:%s\n", list); // 通过“比较器(descagecomparator)”,对list进行排序 // descagecomparator的排序方式是:根据“age”的降序排序 collections.sort(list, new descagecomparator()); system.out.printf("desc(age) sort, list:%s\n", list); // 判断两个person是否相等 testequals(); } /** * @desc 测试两个person比较是否相等。 * 由于person实现了equals()函数:若两person的age、name都相等,则认为这两个person相等。 * 所以,这里的p1和p2相等。 * * todo:若去掉person中的equals()函数,则p1不等于p2 */ private static void testequals() { person p1 = new person("eee", 100); person p2 = new person("eee", 100); if (p1.equals(p2)) { system.out.printf("%s equal %s\n", p1, p2); } else { system.out.printf("%s not equal %s\n", p1, p2); } } /** * @desc person类。 * person实现了comparable接口,这意味着person本身支持排序 */ private static class person implements comparable<person>{ int age; string name; public person(string name, int age) { this.name = name; this.age = age; } public string getname() { return name; } public int getage() { return age; } public string tostring() { return name + " - " +age; } /** * 比较两个person是否相等:若它们的name和age都相等,则认为它们相等 */ boolean equals(person person) { if (this.age == person.age && this.name == person.name) return true; return false; } /** * @desc 实现 “comparable<string>” 的接口,即重写compareto<t t>函数。 * 这里是通过“person的名字”进行比较的 */ @override public int compareto(person person) { return name.compareto(person.name); //return this.name - person.name; } } /** * @desc ascagecomparator比较器 * 它是“person的age的升序比较器” */ private static class ascagecomparator implements comparator<person> { @override public int compare(person p1, person p2) { return p1.getage() - p2.getage(); } } /** * @desc descagecomparator比较器 * 它是“person的age的升序比较器” */ private static class descagecomparator implements comparator<person> { @override public int compare(person p1, person p2) { return p2.getage() - p1.getage(); } } }
下面对这个程序进行说明。
1.person类定义。如下:
private static class person implements comparable<person>{ int age; string name; ... /** * @desc 实现 “comparable<string>” 的接口,即重写compareto<t t>函数。 * 这里是通过“person的名字”进行比较的 */ @override public int compareto(person person) { return name.compareto(person.name); //return this.name - person.name; } }
说明:
(1) person类代表一个人,persong类中有两个属性:age(年纪) 和 name“人名”。
(2) person类实现了comparable接口,因此它能被排序。
2.在main()中,我们创建了person的list数组(list)。如下:
// 新建arraylist(动态数组) arraylist<person> list = new arraylist<person>(); // 添加对象到arraylist中 list.add(new person("ccc", 20)); list.add(new person("aaa", 30)); list.add(new person("bbb", 10)); list.add(new person("ddd", 40));
3.接着,我们打印出list的全部元素。如下:
// 打印list的原始序列 system.out.printf("original sort, list:%s\n", list);
4.然后,我们通过collections的sort()函数,对list进行排序。
由于person实现了comparable接口,因此通过sort()排序时,会根据person支持的排序方式,即 compareto(person person) 所定义的规则进行排序。如下:
// 对list进行排序 // 这里会根据“person实现的comparable<string>接口”进行排序,即会根据“name”进行排序 collections.sort(list); system.out.printf("name sort, list:%s\n", list);
5.对比comparable和comparator
我们定义了两个比较器 ascagecomparator 和 descagecomparator,来分别对person进行 升序 和 降低 排序。
6.ascagecomparator比较器
它是将person按照age进行升序排序。代码如下:
/** * @desc ascagecomparator比较器 * 它是“person的age的升序比较器” */ private static class ascagecomparator implements comparator<person> { @override public int compare(person p1, person p2) { return p1.getage() - p2.getage(); } }
7.descagecomparator比较器
它是将person按照age进行降序排序。代码如下:
/** * @desc descagecomparator比较器 * 它是“person的age的升序比较器” */ private static class descagecomparator implements comparator<person> { @override public int compare(person p1, person p2) { return p2.getage() - p1.getage(); } }
8.运行结果 运行程序,输出如下:
original sort, list:[ccc - 20, aaa - 30, bbb - 10, ddd - 40] name sort, list:[aaa - 30, bbb - 10, ccc - 20, ddd - 40] asc(age) sort, list:[bbb - 10, ccc - 20, aaa - 30, ddd - 40] desc(age) sort, list:[ddd - 40, aaa - 30, ccc - 20, bbb - 10] eee - 100 equal eee - 100
上一篇: docker简介和常用命令“易读”
下一篇: thinkphp分页集成实例
推荐阅读
-
对比Java中的Comparable排序接口和Comparator比较器接口
-
java中实现Comparable接口实现自定义排序的示例
-
详解Java中Comparable和Comparator接口的区别
-
java中实现Comparable接口实现自定义排序的示例
-
java 中接口和抽象类的区别与对比
-
详解Java中Comparable和Comparator接口的区别
-
集合中按照商品价格排序,按照学生编号排序,Collections集合里的sort方法,Comparator
接口,Comparable 接口, -
java比较器Comparable接口与Comaprator接口的深入分析
-
java比较器Comparable接口与Comaprator接口的深入分析
-
【JAVA】用Comparable接口学生的成绩做降序排序!请正确指定泛型;用Comparator实现按照姓名排序,请正确指定泛型!