在实际应用中,我们往往有需要比较两个自定义对象大小的地方。而这些自定义对象的比较,就不像简单的整型数据那么简单,它们往往包含有许多的属性,我们一般都是根据这些属性对自定义对象进行比较的。所以Java中要比较对象的大小或者要对对象的集合进行排序,需要通过比较这些对象的某些属性的大小来确定它们之间的大小关系。
一般,Java中通过接口实现两个对象的比较,比较常用就是Comparable接口和Comparator接口。首先类要实现接口,并且使用泛型规定要进行比较的对象所属的类,然后类实现了接口后,还需要实现接口定义的比较方法(compareTo方法或者compare方法),在这些方法中传入需要比较大小的另一个对象,通过选定的成员变量与之比较,如果大于则返回1,小于返回-1,相等返回0。
1、Comparable和Comparator都是用来实现集合中元素的比较、排序的。
2、Comparable是在类内部定义的方法实现的排序,位于java.lang下。
3、Comparator是在类外部实现的排序,位于java.util下。
4、实现Comparable接口需要覆盖compareTo方法,实现Comparator接口需要覆盖compare方法。
1、什么是Comparable接口
此接口强行对实现它的每个类的对象进行整体排序。此排序被称为该类的自然排序,类的 compareTo方法被称为它的自然比较方法 。实现此接口的对象列表(和数组)可以通过 Collections.sort(和 Arrays.sort )进行自动排序。实现此接口的对象可以用作有序映射表中的键或有序集合中的元素,无需指定比较器。
如String、Integer自己就实现了Comparable接口,可完成比较大小操作。自定义类要在加入list容器中后能够排序,也可以实现Comparable接口,在用Collections类的sort方法排序时若不指定Comparator,那就以自然顺序排序。所谓自然顺序就是实现Comparable接口设定的排序方式。
2、实现什么方法
int compareTo(T o)
比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
参数:o - 要比较的对象。
返回:负整数、零或正整数,根据此对象是小于、等于还是大于指定对象。
抛出:ClassCastException - 如果指定对象的类型不允许它与此对象进行比较。
/**
*
* @Description: 自定义类实现Comparable接口实现比较大小
*
* @author: zxt
*
* @time: 2018年5月15日 上午9:18:42
*
*/
public class Person implements Comparable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 实现Comparable接口,在类的内部实现比较逻辑,通过覆盖compareTo方法,如此一来,自定义的两个类可以比较大小
* 将自定义的类放在集合类中,可以使用Collections的sort来自然排序,不用提供比较器。自然排序的实现即compareTo方法
*/
@Override
public int compareTo(Person anotherPerson) {
// 先比较name的大小,若一样再比较age的大小
// 使用字符串的比较
int flag = name.compareTo(anotherPerson.getName());
if(flag == 0) {
// 名字相等,则比较年龄
return age - anotherPerson.getAge();
} else {
// 名字不一样,返回名字比较结果
return flag;
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "[ name:" + name + ", age:" + age + " ]";
}
}
public class ComparableTest {
public static void main(String[] args) {
List list = new ArrayList();
list.add(new Person("zhangsan", 45));
list.add(new Person("lisi", 34));
list.add(new Person("alilang", 11));
list.add(new Person("woshishui", 45));
list.add(new Person("zhangsan", 12));
list.add(new Person("lisi", 50));
list.add(new Person("wangwu", 23));
System.out.println("初始列表:");
for(Person person : list) {
System.out.print(person + "\t");
}
System.out.println();
System.out.println("排序后:");
Collections.sort(list);
for(Person person : list) {
System.out.print(person + "\t");
}
}
}
Comparator是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足要求时,可写一个比较器来完成两个对象之间大小的比较。Comparator体现了一种策略模式(strategy design pattern),就是不改变对象自身,而用一个策略对象(strategy object)来改变它的行为。
与上面的Comparable接口不同的是:
1)、Comparator位于包java.util下,而Comparable位于包java.lang下。
2)、Comparable接口将比较代码嵌入需要进行比较的类的自身代码中,而Comparator接口在一个独立的类中实现比较。
3)、如果前期类的设计没有考虑到类的Compare问题而没有实现Comparable接口,后期可以通过Comparator接口来实现比较算法进行排序,并且为了使用不同的排序标准做准备,比如:升序、降序。
4)、Comparable接口强制进行自然排序,而Comparator接口不强制进行自然排序,可以指定排序顺序。
/**
*
* @Description: 自定义类实现实现比较大小,使用Comparator接口可以不修改源代码
*
* @author: zxt
*
* @time: 2018年5月15日 上午9:18:42
*
*/
public class Cat{
private String name;
private int age;
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "[ name:" + name + ", age:" + age + " ]";
}
}
import java.util.Comparator;
/**
*
* @Description: 实现Comparator接口,实现一个比较器
*
* @author: zxt
*
* @time: 2018年5月15日 上午9:49:45
*
*/
public class CatComparator implements Comparator {
/**
* 实现Comparator接口,在类的外部实现比较逻辑,通过覆盖compare方法,
* 将自定义的类放在集合类中,使用Collections的sort来排序时,需要提供集合类本身,以及该比较器。
*/
@Override
public int compare(Cat cat1, Cat cat2) {
// 先比较name的大小,若一样再比较age的大小
// 使用字符串的比较
int flag = cat1.getName().compareTo(cat2.getName());
if(flag == 0) {
// 名字相等,则比较年龄
return cat1.getAge() - cat2.getAge();
} else {
// 名字不一样,返回名字比较结果
return flag;
}
}
}
public class ComparatorTest {
public static void main(String[] args) {
List list = new ArrayList();
list.add(new Cat("xiaohong", 12));
list.add(new Cat("xiaohua", 32));
list.add(new Cat("dahua", 33));
list.add(new Cat("dahuang", 45));
list.add(new Cat("dahua", 7));
list.add(new Cat("xiaohong", 45));
list.add(new Cat("xiaohei", 22));
System.out.println("初始列表:");
for(Cat cat : list) {
System.out.print(cat + "\t");
}
System.out.println();
System.out.println("排序后:");
Collections.sort(list, new CatComparator());
for(Cat cat : list) {
System.out.print(cat + "\t");
}
}
}
两种方法各有优劣,用Comparable 简单,只要实现Comparable接口的对象直接就成为一个可以比较的对象,但是需要修改源代码;用Comparator 的好处是不需要修改源代码,而是另外实现一个比较器,当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了。并且在Comparator里面用户可以自己实现复杂的可以通用的逻辑,使其可以匹配一些比较简单的对象,那样就可以节省很多重复劳动了。总而言之Comparable是自已完成比较,Comparator是外部程序实现比较。