Java对象排序之Comparator与Comparable

前言

关于Java中的排序,我们常见的就是对ArrayList进行排序,对于Array,我们可以使用Arrays.sort(数组)进行排序;对于List,我们可以使用Collections.sort(list)进行排序,如果是需要对一个实体类的对象进行排序呢?

两种实现方法

有两种方法可以实现。

  1. 一种方法是类实现Comparable<T>接口,然后调用Collections.sort(List)方法进行排序。
  2. 另一种方法是类不实现Comparable接口,而在排序时使用Collections.sort(List, Comparator<T>)方法,并实现其中的Comparator<T>接口。

Comparable接口有一个comparTo(Object o)方法,它返回整数类型。对于表达式x.compareTo(y),如果返回值为0,则表示x和y相等,如果返回值大于0,则表示x大于y,如果返回值小于0,则表示x小于y;这是一个比较器接口。

排序实现

模拟一个Person对象,要对其进行排序,排序的条件是先根据id排序,当id相等的情况下载根据年龄进行排序,当年龄相等再根据名字。

通过类实现Comparable接口进行排序

Person类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
public static class Person implements Comparable<Person> {
//非 int、float等基本类型
private Integer id;
private Integer age;
private String name;

public Person(Integer age, String name, Integer id) {
this.age = age;
this.name = name;
this.id = id;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return "Person [id=" + id + ", age=" + age + ", name=" + name + "]";
}

/*
* (non-Javadoc)
*
* @see java.lang.Comparable#compareTo(java.lang.Object)
* 先根据id比较,如果id相同,就比较age,最后再比较name(按姓名的字典序升序排序)
*/
@Override
public int compareTo(Person o) {
if (this.id > o.getId()) {
return 1;
} else if (this.id < o.getId()) {
return -1;
} else {
if (this.age > o.getAge()) {
return 1;
} else if (this.age < o.getAge()) {
return -1;
} else {
return this.name.compareTo(o.getName());
}
}
}

}

在客户端中测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Compareto {
public static void main(String[] args) {
List<Person> students = new ArrayList<>();
students.add(new Person(25, "LuanYu",0));
students.add(new Person(26, "LuanYu",0));
students.add(new Person(26, "LuanYu",5));
students.add(new Person(27, "LiuBei",1));
students.add(new Person(27, "Zhangi",1));

Collections.sort(students);
for(Person student:students){
System.out.println(student.toString());
}
}

输出结果

1
2
3
4
5
Person [id=0, age=25, name=LuanYu]
Person [id=0, age=26, name=LuanYu]
Person [id=1, age=27, name=LiuBei]
Person [id=1, age=27, name=Zhangi]
Person [id=5, age=26, name=LuanYu]

可以看到,按姓名的字典序升序排序。使用这用方法排序不能使用基本类型(int, float)等。

通过Comparable接口实现排序

Person类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* 没有实现Comparable<T>接口的Person类
*/
public static class Person {
private Integer id;
private Integer age;
private String name;

public Person(Integer age, String name, Integer id) {
this.age = age;
this.name = name;
this.id = id;
}

@Override
public String toString() {
return "Person [id=" + id + ", age=" + age + ", name=" + name + "]";
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

}

main方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public static void main(String[] args) {
List<Person> persons = new ArrayList<>();
persons.add(new Person(25, "LsanYu", 0));
persons.add(new Person(26, "LuanYu", 0));
persons.add(new Person(26, "LuanYu", 5));
persons.add(new Person(27, "LiuBei", 1));
persons.add(new Person(27, "Zhangi", 1));

Collections.sort(persons, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
// 这里是需要做处理的部分
if (o1.getId() > o2.getId()) {
return 1;
}else if (o1.getId() < o2.getId()) {
return -1;
}else {
if (o1.getAge()>o2.getAge()) {
return 1;
}else if (o1.getAge() < o2.getAge()) {
return -1;
}else {
return o1.getName().compareTo(o2.getName());
}
}
}
});
for(Person person:persons){
System.out.println(person.toString());
}
}

输出结果

1
2
3
4
5
Person [id=0, age=25, name=LsanYu]
Person [id=0, age=26, name=LuanYu]
Person [id=1, age=27, name=LiuBei]
Person [id=1, age=27, name=Zhangi]
Person [id=5, age=26, name=LuanYu]

总结

  1. 第二种方法通过重新定义Collections.sort(List,Comparator)实现排序,当需求有变需要按照其他规则(比如id)排序时,只有重新定义一个Comaprator,而不用修改Person类,然后修改客户端代码,这样就基本满足了开闭原则,即可以通过增加新类方便的扩充新功能,满足新需求而不用修改原来的代码。
  2. 如果我们采用让Person实现Comaparable接口,则在想采用新的排序规则时,必须修改Person里的comareTo(Object o)方法,这样就违反了开闭原则。综上,第二种方法比第一种方法更加灵活。
0%