本文用来简单记录Java
中Comparator
和Comparable
接口特点与使用。
首先,分别查看官方对这两个接口的描述定义:
一、Comparator接口
This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.
A comparison function, which imposes a total ordering on some collection of objects.
可以看出官方对该接口的描述是,它是一种比较函数,用于对一些集合中的对象进行总的排序。即:对集合中的元素进行排序。通过其源码可以看出,除了compare(T o1,T o2)
方法,其他方法都给了默认实现。
int compare(T o1, T o2);
所以要想使用该接口,就得实现该接口的此方法。那么,该接口的作用是什么呢?
实现接口Comparator<T>
类型的任何类都必须要有一个compare
的方法,该方法有两个泛型类型(AnyType)的参数 并返回一个int
型的量,遵守和compareTo
(Comparable接口中需要实现的方法)相同的约定。
简而言之,是对集合中的元素,进行比较。该接口用来返回int
类型的结果。当返回是一个正数时,表明o1
在集合中的排列在o2
之前(注意:这里只是说o1
排列在o2
之前,并没有说o1
大于/小于o2
,因此这里的比较,只是用来确定元素在集合中的排列顺序,说大小的比较其实并不太准确);当返回是一个负数时,表明o2
在集合中排列在o1
之前;如果返回0,那么o1
和o2
的排列先后顺序没有关系,简单理解成两个对象"相等"。
我们以最简单的例子,来对上面的说法进行实践:
Java
中的java.util.Arrays
中的sort
方法如果对int
类型的数组进行排序,默认是升序排序,这里我们自定义一个Comparator
接口来实现降序排序。
- 自定义
Comparator
接口
public class MyComparator implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
if (o1 - o2 > 0) { // 该条件表明o1大于o2,o1排列在o2之后
return -1;
} else if (o1 - o2 < 0) { // 该条件表明o1小于o2,o1排列在o2之前
return 1;
} else { // 顺序无关
return 0;
}
}
}
- 使用自定的接口
public class MyComparatorTest {
public static void main(String[] args) {
Random random = new Random();
Integer[] res = new Integer[20];
for (int i = 0; i < 20; ++i) {
res[i] = random.nextInt(50) + 50; // 随机生成 50 到 100 之间的随机整数
}
Arrays.sort(res, new MyComparator());
System.out.println(Arrays.toString(res));
}
}
=====结果=====
[96, 87, 87, 85, 84, 80, 80, 78, 78, 74, 68, 65, 65, 65, 64, 63, 53, 53, 53, 51]
所以,Comparator
用于指定集合中对象的排列方式,并且我们在使用Comparator
接口时,是专门定义类(工具类)去实现该接口,使得该工具类与被比较对象的类进行了分离。如果对被需要比较的对象修改了比较策略,那么只需要修改我们的工具类即可,因此大大降低了对象之间的耦合性(与Comparable
接口最大的不同之处),更具有灵活性。
二、Comparable接口
This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class’s natural ordering, and the class’s
compareTo
method is referred to as its natural comparison method.
从上面的实现中看出,对实现该接口的对象进行一个"总"的排序。即:如果想要使用该接口的排列策略,让需要排列的对象的类实现该接口。
其源码:
/**
* Compares this object with the specified object for order. Returns a
* negative integer, zero, or a positive integer as this object is less
* than, equal to, or greater than the specified object.
**/
public int compareTo(T o);
使用方式同Comparator
接口,只是这里是实现compareTo
接口。
这里我们自定义一个People
类:
public class People implements Comparable<Object>{
private int age;
private String name;
private double salary;
public People() {
}
public People(int age, String name, double salary) {
this.age = age;
this.name = name;
this.salary = salary;
}
/**
getter / setter / toString 方法的省略
**/
@Override
public int compareTo(Object o) {
People tempPeople = (People) o;
if (this.age > tempPeople.getAge()) {
return 1;
} else if (this.age < tempPeople.getAge()) {
return -1;
}
if (this.salary > tempPeople.getSalary()) {
return 1;
} else if (this.salary < tempPeople.getSalary()) {
return -1;
}
return 0;
}
}
我们看出我们自定义的People
类实现了Comparable
接口,实现的比较规则是,先按照年龄的大小进行排序,如果年龄大小相同,按照工资的大小进行排序,否则最终返回0
.(代表此时两个对象"相等")。
接下来来对该类进行测试:
@Test
public void test() {
People p1 = new People(24, "Lisa", 4000d);
People p2 = new People(24, "Lisa", 5000d);
People p3 = new People(25, "Lisa", 5000d);
People[] people = {p1, p2, p3};
Arrays.sort(people);
System.out.println(Arrays.toString(people));
}
====结果====
[People{age=24, name='Lisa', salary=4000.0}, People{age=24, name='Lisa', salary=5000.0}, People{age=25, name='Lisa', salary=5000.0}]
三、总结
Comparable
接口和Comparator
接口区别
-
Comparator
位于包Java.util
下,而Comparable
位于包Java.lang
包下。 -
Comparable
接口将比较代码嵌入需要进行比较的自身代码中,而Comparator
接口在一个独立的类中实现比较。 -
Comparable
接口需要实现重写comparaTo
方法,同时Comparable
是排序接口,若一个类实现了Comparable
接口,该类支持排序,相当于内部比较器,Comparator
相当于外部比较器。Comparable
接口强制进行自然排序,Comparator
不强制,可以指定排序。 -
Comparator
更适用于Java
提供的类使用;Comparable
适用我们自定义的类使用(嵌入在自定义的类中)