1. 两者对比
Comparable和Comparator都是用来实现集合中元素的比较、排序的。Comparable是在集合内部定义的方法实现的排序,位于java.util下。Comparator是在集合外部实现的排序,位于java.lang下。
- Comparable是一个对象本身就已经支持自比较所需要实现的接口,如String、Integer等基本类型的包装类都自己就实现了Comparable接口,可完成比较大小操作。自定义类要在加入list容器中后能够排序,也可以实现Comparable接口,在用Collections类的sort方法排序时若不指定Comparator,那就以自然顺序排序。所谓自然顺序就是实现Comparable接口设定的排序方式。
- Comparator是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足要求时,可写一个比较器来完成两个对象之间大小的比较。Comparator体现了一种策略模式(strategy design pattern),就是不改变对象自身,而用一个策略对象(strategy object)来改变它的行为。总而言之Comparable是自已完成比较,Comparator是外部程序实现比较
2. 代码演示
// 测试Comparable
public class CompareTest {
public static void main(String[] args) {
ComparableImpl com1 = new ComparableImpl("name1",12);
ComparableImpl com2 = new ComparableImpl("name1",11);
ComparableImpl com13 = new ComparableImpl("name1",17);
ArrayList<ComparableImpl> lists = new ArrayList<>();
lists.add(com1);
lists.add(com2);
lists.add(com13);
Collections.sort(lists);
lists.forEach(System.out::println);
}
}
class ComparableImpl implements Comparable {
String name;
Integer age;
public ComparableImpl(String name, Integer age) {
this.name = name;
this.age = age;
}
// 根据年龄进行对比
@Override
public int compareTo(Object obj) {
if (obj instanceof ComparableImpl) {
ComparableImpl another = (ComparableImpl) obj;
if (this.age < another.age) {
return -1;
} else if (this.age.equals(another.age)) {
return 0;
} else {
return 1;
}
}
return 0;
}
@Override
public String toString() {
return "ComparableImpl{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
// 测试Comparator
// 不支持自比较的类
public class UnSpportSortObj {
private String name;
private Integer age;
public UnSpportSortObj(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "UnSpportSortObj{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UnSpportSortObj that = (UnSpportSortObj) o;
return Objects.equals(name, that.name) &&
Objects.equals(age, that.age);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
// 实现Comparator 的比较器
class ComparatorImpl implements Comparator<UnSpportSortObj> {
@Override
public int compare(UnSpportSortObj o1, UnSpportSortObj o2) {
return o1.getAge() - o2.getAge();
}
}
// 测试
public class CompareTest {
public static void main(String[] args) {
// 使用Comparator接口进行排序
ArrayList<UnSpportSortObj> list2 = new ArrayList<>();
ComparatorImpl comparator = new ComparatorImpl();
UnSpportSortObj unSpportSortObj1 = new UnSpportSortObj("test1",25);
UnSpportSortObj unSpportSortObj2 = new UnSpportSortObj("test2",18);
UnSpportSortObj unSpportSortObj3 = new UnSpportSortObj("test3",36);
UnSpportSortObj unSpportSortObj4 = new UnSpportSortObj("test4",5);
list2.add(unSpportSortObj1);
list2.add(unSpportSortObj2);
list2.add(unSpportSortObj3);
list2.add(unSpportSortObj4);
list2.forEach(System.out::println);
}
}
3. 两者差别
-
Comparator在集合(即你要实现比较的类)外进行定义的实现,而Comparable接口则是在你要比较的类内进行方法的实现。这样看来Comparator更像是一个专用的比较器。
-
Comparator实现了算法和数据的分离,从代码也可以看出,其实这和第一点是相辅相成的,因为Comparable依赖于某一个需要比较的类来实现。
-
Comparable支持自比较,自比较是指比如String等类里面本身就有CompareTo()方法,直接就可以进行String类对象的比较,这也可以从较之Comparator,Comparable中Arrays.sort()方法中只带数组参数的形式与书上例子更相似这点看出。
-
从第3点延伸,我们可以看到当不满足于自比较函数,如String类时,我们试图改写规则要怎么办——通过Comparator因为它支持外比较,它是分离的。
-
当一个又一个类设计完成后,或许我们最初没有设想到类的比较问题,而没使用Comparable接口,那我们之后可以通过Comparator来完成,而同时无需改变之前完成的类的构建。
-
运用Arrays.sort()方法时,注意二者的参数不同,Comparator多了一个参数,这第二个参数是使用Comparator接口的那个被视为专用比较器的类的对象。