Java中的比较器(Comparable和Comparator)
在Java中,正常情况下,对象不能使用<、>进行比较,排序,而在开发中我们又需要对对象进行排序,比如TreeMap、TreeSet,再往里面添加数据时,需要让添加进去的对象排序好,这时就需要使用两个接口中的一个:Comparable和Comparator。
很多情况下,我们需要对数据进行排序,但是java自带的比较器只能比较基本数据类型,比如我们自己定义一个Student类,如果用默认的Array.sort()方法进行排序,他会按照内存地址进行排序,那么这个排序毫无意义,此时我们就需要自己定义一个比较器,按照我们想要的比较方式来进行排序。
Comparable
所有可以排序的类都实现了java.lang.Comparable接口,Comparable接口中只有一个方法:compareTo(Object obj),该方法返回0表示this==obj、返回正数表示this>obj、返回负数表示this<obj,实现了Comparable接口的类通过实现comparaTo方法从而确定该类对象的排序方式。
一般被集合元素类所实现。
public class Student implements Comparable<Student>{
/**
* 编号
*/
private int id;
/**
* 姓名
*/
private String name;
/**
* 通过学生编号进行排序
* @param o
* @return
*/
@Override
public int compareTo(Student o) {
return this.id - o.id;
}
}
Comparator
Comparator可以认为是一个外比较器,在一个对象不支持自己和自己比较(没有实现Comparable接口),但是又想对两个对象进行比较的情况下可以使用,Comparator接口里有一个compara(T o1, T o2)方法,方法有两个参数T o1和T o2,是泛型的表示方式,分别表示待比较的两个对象,方法返回值和Comparable接口一样是int,有三种情况:
- o1大于o2,返回正整数
- o1等于o2,返回零
- o1小于o2,返回负整数
Comparator接口一般有两种实现方式,单独实现,或者匿名内部类方式实现。
匿名内部类实现方式:
public class TreeSetDemo {
public static void main(String[] args) {
Set set = new TreeSet(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Clazz c1 = (Clazz) o1;
Clazz c2 = (Clazz) o2;
return c1.getId() - c2.getId();
}
});
set.add(new Clazz(1,"name1"));
set.add(new Clazz(2,"name2"));
set.add(new Clazz(3,"name3"));
// 遍历set
for (Object obj : set) {
System.out.println(obj);
}
}
}
单独实现:
public class TreeSetDemo {
public static void main(String[] args) {
Set set = new TreeSet(new ClazzComparatorOrder(false));
set.add(new Clazz(1,"name1"));
set.add(new Clazz(2,"name2"));
set.add(new Clazz(3,"name3"));
// 遍历set
for (Object obj : set) {
System.out.println(obj);
}
}
/**
* 排序器,静态内部类
*/
private static class ClazzComparatorOrder implements Comparator {
/**
* 正向或逆向排序的标志
*/
private boolean flag;
/**
* 排序器构造方法
* @param flag 正向或逆向排序的标志
*/
private ClazzComparatorOrder(boolean flag) {
this.flag = flag;
}
@Override
public int compare(Object o1, Object o2) {
Clazz c1 = (Clazz) o1;
Clazz c2 = (Clazz) o2;
if (this.flag) {
// 正向
return c1.getId() - c2.getId();
} else {
// 逆向
return c2.getId() - c1.getId();
}
}
}
}
好处:可以通过构造方法输入true或者false来控制正向或逆向排序。
Comparable 与 Comparator的区别
-
如果对象数组需要排序,那么就必须设置排序规则,就要使用这两种比较器。
-
对于Comparable接口来说,它往往是进行比较类需要实现的接口,它仅包含一个有comparaTo()方法,只有一个参数。
-
对于Comparator接口来说,它的实现者被称为比较器,它包含一个compara()方法,有两个参数,Comparator接口一般不会被集合元素类所实现,而是单独实现或者匿名内部类实现
-
Comparable接口的方式一旦实现,就可以保证Comparable的实现类在任何位置都可以比较大小。
-
Comparator接口属于临时性比较。
-
如果实现类没有实现Comparable接口,又想对两个类进行比较(或者实现类实现了Comparable接口,但是对compareTo方法内的比较算法不满意),那么可以实现Comparator接口,自定义一个比较器,写比较算法。
-
实现Comparable接口的方式比实现Comparator接口的耦合性要强一些,如果要修改比较算法,要修改Comparable接口的实现类,而实现Comparator的类是在外部进行比较的,不需要对实现类有任何修改。从这个角度说,其实有些不太好,尤其在我们将实现类的.class文件打成一个.jar文件提供给开发者使用的时候。