一.概述
Java 中的排序是由 Comparable 和 Comparator 这两个接口来实现的。
Comparable表示可被排序的,实现该接口的类的对象自动拥有排序功能,属于内部顺序,但需要手动实现接口,侵入性比较强。
Comparator则表示一个比较器,一般情况, 这个比较器将作为一个参数进行传递。对待比较累的侵入性弱,但对算法代码实现侵入性强。
二.Comparable(自然排序)
源码如下:
public interface Comparable<T> {
public int compareTo(T o);
}
- Comparable 的中文意思就是可被排序的,代表本身支持排序功能。只要我们的类实现了这个接口,那么这个类的对象就会自动拥有了可被排序的能力。而且这个排序被称为类的自然顺序。
- 这个类的对象的列表可以被Collections.sort()和Arrays.sort()来执行排序。
- 从源码中可以看到,该接口只有一个抽象方法compareTo() 这个方法主要就是为了定义我们的类所要排序的方式。compareTo()方法用于比较当前元素 a与指定元素 b的大小,结果为int值,如果a >b,int值>0; 如果a=b, int值=0;如果a<b, int值<0。
三.Comparator(定制排序)
在实际开发中,遇到当元素的类型实现了 Comparable 接口,但是它的排序方式不适合当前的操作;或者根本没有实现 Comparable接口,而又不方便修改代码。那么可以考虑使用定制一个 Comparator 的对象进行排序。
public interface Comparator<T> {
int compare(T o1, T o2);
boolean equals(Object obj);
}
Comparator 中文译为比较器,它可以作为一个参数传递到Collections. sort()和Arrays.sort()方法,来指定某个类的对象的列表的排序方式。
四.二者比较
- Comparable 可以看做是内部比较器,Comparator 可以看做是外部比较器。
一个类, 可以通过实现 Comparable 接口来自带有序性,也可以通过额外指定 - Comparator 来附加有序性。二者的作用其实是一致的, 所以不要混用。
五.总结
- Comparable为可排序的,实现该接口的类的对象自动拥有可排序功能。
- Comparator为比较器,实现该接口可以定义一个针对某个类的排序方式。
- Comparator与Comparable同时存在的情况下,前者优先级高。
- Comparable和Comparator接口是用来对自定义的类class进行大小比较的。
- Comparator和 Comparable的区别:Comparator定义在类的外部,而Comparable定义在类的内部。
六.具体实现
1.Comparable 定义在类的内部,需要覆写compareTo方法
用户自定义类型想要按照大小进行比较时,在定义类时,需要实现Comparable 接口 ,然后在类中重写compareTo方法比较规则由程序员自己定,例如,下列程序,按照User的年龄升序比较 不然会抛异常:
java.lang.ClassCastException: comparable.User cannot be cast to java.lang.Comparable
*/
public class Test01 {
public static void main(String[] args) {
TreeSet<User> treeSet = new TreeSet<>();
User user1 = new User(20);
User user2 = new User(10);
User user3 = new User(35);
User user4 = new User(29);
User user5 = new User(25);
treeSet.add(user1);
treeSet.add(user2);
treeSet.add(user3);
treeSet.add(user4);
treeSet.add(user5);
for (User user:treeSet) {
System.out.println(user);
}
}
}
//User类实现了Comparable接口,则只需要在类内部覆写compareTo方法,即可进行对象的比较
class User implements Comparable<User>{
private int age;
private String name;
public User() {
}
public User(int age) {
this.age = age;
}
public User(int age,String name) {
this.age = age;
this.name = name;
}
/* @Override
//倘若有多个属性的比较规则,按照如下方式写排序规则
public int compareTo(User o) {
if (this.age == o.age) {
//String类型内部已经重写了compareTo方法,比较的时候直接调用方法即可
//当年龄相等的时候比较name
return this.name.compareTo(o.name);
}else {
//年龄不想等就按照年龄比较
return this.age - o.age;
}
}*/
@Override
public int compareTo(User o) {
return this.age - o.age;//升序
// return o.age - this.age;//降序
}
@Override
public String toString() {
return "User{" +
"age=" + age +
'}';
}
}
2.Comparator 定义在类的外部
比较器Comparator
TreeMap的key或者TreeSet集合中的自定义类型的元素想要排序有两种实现方式:
1.实现java.lang.Comparable接口
2.Comparator比较器 有两种方式
方式一:单独写一个比较器,传入集合
方式二:创建集合的时候编写一个Comparator匿名内部类传入集合
public class Test02 {
public static void main(String[] args) {
WuGui wuGui1 = new WuGui(1000);
WuGui wuGui2 = new WuGui(500);
WuGui wuGui3 = new WuGui(800);
//创建TreeSet集合的时候,需要使用这个比较器
//TreeSet<WuGui> wuGuis = new TreeSet<>(); 这样不行,因为没有通过通过构造方法,传递比较器进去
System.out.println("===============方式1比较器=================");
//方式1:单独写一个比较器,传入集合
TreeSet<WuGui> wuGuis0 = new TreeSet<>(new WuGuiComparator());
wuGuis0.add(new WuGui(1800));
wuGuis0.add(new WuGui(8200));
wuGuis0.add(new WuGui(8100));
for (WuGui wuGui99: wuGuis0) {
System.out.println(wuGui99);
}
System.out.println("===============方式2比较器=================");
//方式2:匿名内部类,传入集合
TreeSet<WuGui> wuGuis = new TreeSet<>(new Comparator<WuGui>() {
@Override
public int compare(WuGui o1, WuGui o2) {
return o1.getAge() - o2.getAge();
}
});
wuGuis.add(wuGui1);
wuGuis.add(wuGui2);
wuGuis.add(wuGui3);
for (WuGui wuGui : wuGuis) {
System.out.println(wuGui);
}
}
}
class WuGui {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public WuGui(int age) {
this.age = age;
}
@Override
public String toString() {
return "小乌龟{" +
"age=" + age +
'}';
}
}
//在WuGui的类外单独编写一个比较器
class WuGuiComparator implements Comparator<WuGui> {
@Override
public int compare(WuGui o1, WuGui o2) {
//指定比较规则
//按照年龄排序
return o1.getAge() - o2.getAge();
}
}