目录
1 介绍
2 Comparable接口
3 Comparator接口
4 总结
1 介绍
有这样2个人,一个人光头,一个人有黑色头发,现在不允许染发,只允许光头的带假发,理由是有头发的人没有必要再带假发,那么谁可以有多种颜色的头发?在这种情况下,有头发的人,因为他的头发和自身绑定在一起,是无法在换头发的;而光头的头发(假发套)和其自身是不绑定的,可以根据自己喜欢换不同颜色的发套。有头发的人叫Comparable,光头不是孟飞,也不是乐嘉,叫Comparator。
Comparable和Comparator是java中2个比较接口。Comparable是和具体类绑定的,我们称为“静态绑定”(如上图中有头发的人,头发是Comparable,头是具体的类)。而对于Comparator,具体的类在需要是可选择不同的Comparator绑定,是“动态绑定”(策略模式)(如上图中光头的人,假发是Comparator,头是具体的类,可根据需要选择不同的假发)。两者相比,Comparator比Comparable灵活,而且具体类可以在需要时选择不同的Comparator。
2 Comparable接口
java.lang. Comparable接口定义类的自然顺序,实现该接口的类就可以按这种方式排序。Comparable只包含一个方法:
- public interface Comparable<T> {
- public int compareTo(T o);
- }
- import java.util.Arrays;
- /**
- * @version 1.0
- * @date 2012-11-15 下午2:25:27
- * @fuction 实现Comparable接口 (先按序号比较,序号相等在比较姓名) */
- public class Student implements Comparable
- {
- //学号
- int num;
- //姓名
- String name;
- //constructor
- public Student(int num,String name)
- {
- this.num=num;
- this.name=name;
- }
- //重写java.lang中的接口Comparable的方法compareTo,定制比较的规则.但必须遵守比较规则(比较结果大返回正数,相等返回0,小返回负数)
- public int compareTo(Object o) {
- Student s=(Student)o;
- int result=num>s.num ? 1:(num==s.num ? 0: -1);
- //学号相等时,按名字排序
- if(0==result)
- {
- //利用String的compareTo方法进行字符的比较
- result=name.compareTo(s.name);
- }
- return result;
- }
- @Override
- public String toString() {
- return "Student [num=" + num + ", name=" + name + "]";
- }
- /**
- * @param args
- */
- public static void main(String[] args) {
- Student[] test=new Student[]{new Student(2, "wangwu"),
- new Student(1, "lisi"),
- new Student(1, "goudan") };
- //排序
- Arrays.sort(test);
- //打印
- for(int i=0;i<test.length;i++)
- {
- System.out.println(test[i]);
- }
- //搜索姓名为“wangwu”的学生
- int index=Arrays.binarySearch(test,new Student(2,"wangwu"));
- System.out.println("查找的学生在数组中的位置:"+index);
- }
- }
3 Comparator接口
java.util.Comparator接口只包含2个方法
- int compare(T o1, T o2);
- boolean equals(Object obj);
int compare(T o1, T o2);比较用来排序的两个参数。
boolean equals(Object obj);指示是否其他对象“等于”此 Comparator。
实现了compare接口的类具体的实现是在compare方法中自定义比较算法,然后将Comparator对象(实现了java.util.Comparator接口的对象)作为一个参数传递给欲比较或排序对象collection的某些排序方法。某些排序方法指的是能够接受java.util.Comparator参数的方法,比如:java.util. Arrays的public static void sort(Object[] a, Comparator c)和Collections的sort方法。
例子
- import java.util.Arrays;
- import java.util.Comparator;
- /**
- * @version 1.0
- * @date 2012-11-15 下午11:21:09
- * @fuction 实现Comparator接口的比较算法
- *按学号排序 先按学号排序,学号相等时,按姓名排序 o1>o2返回1,o1=o2返回0,o1>o2返回-1
- */
- public class ByNumComparator implements Comparator {
- public int compare(Object o1, Object o2) {
- Student s1 = (Student) o1;
- Student s2 = (Student) o2;
- // 按学号排序
- int result = s1.num > s2.num ? 1 : (s1.num == s2.num ? 0 : -1);
- // 学号相等时,按名字排序
- if (result == 0) {
- int copmpareName=s1.name.compareTo(s2.name);
- //利用String的compareTo方法进行字符的比较
- if(copmpareName>0)
- result=1;
- else if (copmpareName==0)
- result=0;
- else
- result=-1;
- }
- return result;
- }
- public static void main(String[] args) {
- Student[] test = new Student[] { new Student(2, "wangwu"),
- new Student(1, "lisi"), new Student(1, "goudan") };
- // 排序
- Arrays.sort(test, new ByNumComparator());
- // 打印
- System.out.println("排序之后");
- for (int i = 0; i < test.length; i++) {
- System.out.println(test[i]);
- }
- }
- }
输出结果:
排序之后
Student [num=1, name=goudan]
Student [num=1, name=lisi]
Student [num=2, name=wangwu]
4 总结
一般在对对象进行比较或排序时,需要对象实现Comparable接口或者在使用排序方法(比如Arrays的sort)方法时,传入实现了Comparator接口的类的对象。
Comparable & Comparator 都是用来实现集合中元素的比较、排序的,只是 Comparable 是在集合内部定义的方法实现的排序,Comparator 是在集合外部实现的排序,所以,如想实现排序,就需要在集合外定义 Comparator 接口的方法或在集合内实现 Comparable 接口的方法。
Comparator位于包java.util下,而Comparable位于包 java.lang下
Comparable 是一个对象本身就已经支持自比较所需要实现的接口(如 String、Integer 自己就可以完成比较大小操作,已经实现了Comparable接口)
自定义的类要在加入list容器中后能够排序,可以实现Comparable接口,在用Collections类的sort方法排序时,如果不指定Comparator,那么就以自然顺序排序,如API所说:
Sorts the specified list into ascending order, according to the natural ordering of its elements. All elements in the list must implement the Comparable interface
这里的自然顺序就是实现Comparable接口设定的排序方式。
而 Comparator 是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足你的要求时,你可以写一个比较器来完成两个对象之间大小的比较。
可以说一个是自已完成比较,一个是外部程序实现比较的差别而已。
用 Comparator 是策略模式(strategy design pattern),就是不改变对象自身,而用一个策略对象(strategy object)来改变它的行为。
比如:你想对整数采用绝对值大小来排序,Integer 是不符合要求的,你不需要去修改 Integer 类(实际上你也不能这么做)去改变它的排序行为,只要使用一个实现了 Comparator 接口的对象来实现控制它的排序就行了。
// AbsComparator.java
import java.util.*;
public class AbsComparator implements Comparator {
public int compare(Object o1, Object o2) {
int v1 = Math.abs(((Integer)o1).intValue());
int v2 = Math.abs(((Integer)o2).intValue());
return v1 > v2 ? 1 : (v1 == v2 ? 0 : -1);
}
}
可以用下面这个类测试 AbsComparator:
// Test.java
import java.util.*;
public class Test {
public static void main(String[] args) {
//产生一个20个随机整数的数组(有正有负)
Random rnd = new Random();
Integer[] integers = new Integer[20];
for(int i = 0; i < integers.length; i++)
integers[i] = new Integer(rnd.nextInt(100) * (rnd.nextBoolean() ? 1 : -1));
System.out.println("用Integer内置方法排序:");
Arrays.sort(integers);
System.out.println(Arrays.asList(integers));
System.out.println("用AbsComparator排序:");
Arrays.sort(integers, new AbsComparator());
System.out.println(Arrays.asList(integers));
}
}
Collections.sort((List<T> list, Comparator<? super T> c)是用来对list排序的。
如果不是调用sort方法,相要直接比较两个对象的大小,如下:
Comparator定义了俩个方法,分别是 int compare(T o1, T o2)和 boolean equals(Object obj),
用于比较两个Comparator是否相等
true only if the specified object is also a comparator and it imposes the same ordering as this comparator.
有时在实现Comparator接口时,并没有实现equals方法,可程序并没有报错,原因是实现该接口的类也是Object类的子类,而Object类已经实现了equals方法
Comparable接口只提供了 int compareTo(T o)方法,也就是说假如我定义了一个Person类,这个类实现了 Comparable接口,那么当我实例化Person类的person1后,我想比较person1和一个现有的Person对象person2的大小时,我就可以这样来调用:person1.comparTo(person2),通过返回值就可以判断了;而此时如果你定义了一个 PersonComparator(实现了Comparator接口)的话,那你就可以这样:PersonComparator comparator= new PersonComparator();
comparator.compare(person1,person2);。