Comparable与Comparator接口
我们可能会遇到这样的问题:怎么对一个对象数组进行排序? 比如对一个狗类对象数组进行排序,而想到这,我们又会有一个问题:怎么比较两个对象?如果我想自定义标准,怎么办?
与基本类型的比较并排序不同,对象数组没有一个统一的标准来进行比较来排序,此时就可以基于Comparable
接口实现或者基于比较器实现(Comparator
接口)
- 自然排序:基于Comparable接口
- 定制排序:基于Comparator接口
本文均以自定义的Person
类为例:
public class Person {
private String name;
private int age;
public Person(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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Comparable接口
使用了Comparable
接口,意味着此类可排序,使用方法是:在想要实现比较的类中实现Comparable
接口并重写compareTo()
方法
我们先观察一下Comparable
接口的源码:
我们发现,Comparable
接口中只有一个CompareTo
方法
观察完毕后,我们看如下实现代码:
//Person.java
//实现Comparable接口
public class Person implements Comparable<Person> {
private String name;
private int age;
public Person(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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//重写compareTo方法,这里按照name(字符串)比较
@Override
public int compareTo(Person o) {
if(this.name.compareTo(o.name) > 0) {
return 1;
}else if(this.name.compareTo(o.name) < 0) {
return -1;
}else {
return 0;
}
}
}
//Test.java
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
Person[] people = new Person[]{new Person("zhangsan", 23), new Person("lisi", 15),
new Person("wangwu", 42)};
//实现了Comparable接口后,可以通过Arrays类中的排序方法给对象数组排序了
Arrays.sort(people);
for(Person p : people) {
System.out.println(p);
}
}
}
打印结果如下:
-
Comparable
接口后面的<>
是泛型知识,传入要比较的类即可 -
实现
Comparable
接口必须重写CompareTo
方法,方法要求返回int
类型的值,一般内部实现的逻辑:调用方法的对象 > 作为参数的对象,返回正数;调用方法的对象 < 作为参数的对象,返回负数;调用方法的对象 == 作为参数的对象,返回0
-
一个类实现了
Comparable
接口,那么就可以调用Arrays
类中的sort
方法对存放此类对象的数组进行排序 -
一个实现了
Comparable
接口的类只能重写一个compareTo
方法,这也意味着标准被固定
Comparator接口
前面提到,基于Comparable
接口实现比较的标准固定,且不便在原代码修改,这种情况下,我们可以通过Comparator
接口(比较器)实现,方法是:定义一个或多个比较器类,实现Comparator
接口,并重写Compare
方法
我们先观察一下Comparator
接口的一部分源码:
这部分源码显示,Comparator
接口中包含compare
和equals
方法,实现了Comparator
接口的类可以不重写equals
方法,但是一定要重写compare
方法
观察完毕后,我们看如下实现代码:
//Person.java
public class Person {
private String name;
private int age;
public Person(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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
//AgeComparator.java
//以年龄比较的比较器
import java.util.Comparator;
public class AgeComparator implements Comparator<Person> {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge() - o2.getAge();
}
}
//NameComparator.java
//以名字比较的比较器
import java.util.Comparator;
public class NameComparator implements Comparator<Person> {
@Override
public int compare(Person o1, Person o2) {
return o1.getName().compareTo(o2.getName());
}
}
//Test.java
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
Person[] people = new Person[]{new Person("zhangsan", 23), new Person("lisi", 15),
new Person("wangwu", 42)};
//使用时,必须实例化比较器对象
AgeComparator ageComparator = new AgeComparator();
NameComparator nameComparator = new NameComparator();
//正常使用
System.out.println(ageComparator.compare(new Person("张三", 16), new Person("李四", 10)));
//与Arrays类中的sort方法配合使用
Arrays.sort(people, ageComparator);
for(Person p : people) {
System.out.println(p);
}
}
}
打印结果如下:
- 要比较的对象的类不需要实现
Comparator
接口,比较器需要实现Comparator
接口,并在<>
内给出要比较的类,并重写compare
方法 - 重写的
compare
方法有两个参数,分别是要比较的两个对象,重写的compare
方法要求:返回值的正负以及零,表示不同的比较结果。例如,左参数对象大于右参数对象,返回正值;左参数对象小于右参数对象,返回负值;左右参数对象相等,返回0 - 使用时,必须实例化比较器类对象。可以选择直接调用其中的
compare
方法比较单一对象,也可以配合Arrays
类中的sort
方法对对象数组进行排序,此时sort
方法需要两个参数:1. 对象数组 2. 比较器对象 - 比较器可以创建若干个,意味着我们可以定义多个标准,相对灵活一些
区别:
Comparable
相当于 “内部比较器”,Comparator
相当于 “外部比较器”- 对于基于
Comparable
的比较,需要手动实现接口,侵入性比较强,但一旦实现,每次调用该类都有顺序,属于内部顺序- 对于基于
Comparator
的比较,需要实现一个比较器对象,对待比较类的侵入性弱,但对算法代码实现侵入性强
侵入性:让用户代码产生对框架的依赖,这些代码不能直接脱离框架使用,不利于代码的复用
关于对象的比较,数据结构部分会经常用到
我们的SE部分的补充知识到此结束了,小裤马上会发一篇SE语法合集