ArrayList是Java集合框架中使用最为普遍的集合类之一,它的内部用一个动态数组来存储元素。因此ArrayList能够在添加和移除元素的时候进行动态的扩展和缩减。参考官方API。本篇文章将讨论ArrayList中极其重要的操作: 排序。

ArrayList中的元素是Java内置可比较对象

  许多标准Java类实现了Comparable接口,比如String、Integer、Short、Double、Float、Boolean、BigInteger、BigDecimal、File和Date等。这些实现了java.lang包中的Comparable接口的类的实例可以直接进行比较。如果ArrayList中的元素是上述类型,那么可以直接使用Collections.sort()方法对ArrayList进行排序。
排序代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.ArrayList;
import java.util.Collections;
public class SortArrayList() {
private ArrayList arrayList;
public SortArrayList(ArrayList arrayList) {
this.arrayList = arrayList; // 引用传递
}
public ArrayList getArrayList() {
return this.arrayList;
}
// 升序
public ArrayList sortAsc() {
Collections.sort(this.arrayList);
return this.arrayList;
}
// 降序
public ArrayList sortDes() {
Collections.sort(this.arrayList);
return this.arrayList;
}
}

  在上面的类中,我们在构造器中初始化了一个ArrayList对象。在sortAsc()方法中,我们调用了Collections.sort()方法,并传递这个初始化的ArrayList对象为参数,返回排序后的ArrayList。在sortDes()方法中,我们调用重载的Collections.sort()方法让其按照将序对元素排序,第二个参数是由Collections.reverseOrder()返回的Comparator对象。
  到目前为止,所要排序的ArrayList元素都是非常简单的。如果ArrayList中的元素是我们自定义类的对象,应该如何排序呢?

使用Comparable排序ArrayList

  如果想让我们自定义的类对象像上面提到的Java标准类对象一样可以进行比较,就要像标准类那样实现Comparable接口。Comparable是带有单一compareTo()方法的接口,一个实现了Comparable接口的类对象可以与其它同类型的对象进行比较。实现Comparable接口的类需要重写compareTo()方法,这个方法接收一个同类型的对象,并实现当前对象和传递给方法的另一个对象比较的逻辑。compareTo()方法返回int类型的比较结果:

  • 正值表示当前对象比传递给compareTo()的对象大;
  • 负值表示当前对象比传递给compareTo()的对象小;
  • 零表示两个对象相等。

  以我们自定义的User类为例,User类的对象保存在ArrayList中并准备对其进行排序。我们要让User类实现Comparable接口并重写compareTo()方法。
User类

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
public class User implements Comparable {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
@Override
// 基于年龄和名字进行排序
public int compareTo(User user) {
int flag = this.getAge() < user.getAge() ? -1 : (this.getAge() == user.getAge() ? 0 : 1);
if (flag == 0) {
return this.getName().compareTo(user.getName());
}
else
return flag;
}
@Override
public String toString() {
return "Name: " + this.name + ", age: " + this.age;
}
}

  在User类被重写的compareTo()方法中,我们实现了基于年龄和名字的比较逻辑(也可以基于一个成员变量进行比较)。age是int类型,可以通过比较大小判断;name是String类型,通过使用String自带的compareTo()方法比较。很多程序猿将(this.getAge() - user.getAge())作为返回的比较结果。尽管使用这种return语句看上去似乎很吸引人,但是这种方式可能会导致一些错误,让你的程序行为不定,而且更重要的是,这样的错误是很细微的,尤其是在大型的企业应用中很难检测出来,所以建议远离这种语句。接下来我们就可以像对待Java标准类那样通过上述SortArrayList()进行排序了。
  使用ComparableArrayList排序是一种常用的方法。但是你必须知道有某些限制。你想要排序的对象的类必须实现Comparable并覆写compareTo()方法。这意味着你将只能基于一种方式来比较对象。如果有时候要求你按照姓名排序,有时候又要求你按照年龄排序怎么办?Comparable就不是解决的方法了。另外,比较逻辑是需要进行比较的对象的类的一部分,它消除了比较逻辑可复用性的可能。Java通过使用java.util包提供的Comparator接口解决上述的比较需求。

使用Comparator排序ArrayList

  Comparator接口与Comparable接口相似也提供了一个单一的比较方法叫作compare()。然而,与ComparablecompareTo()方法不同的是,这个compare()方法接受两个同类型的不同对象进行比较。
使用了Comparator的User类代码

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
import java.util.Comparator;
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
// 匿名类
public static Comparator ageComparator = new Comparator() {
@Override
public int compare(User user1, User user2) {
// 降序
return (user1.getAge() > uers2.getAge() ? -1 : (user1.getAge() == user2.getAge() ? 0 : 1));
}
};
public static Comparator nameComparator = new Comparator() {
@Override
public int compare(User user1, User user2) {
return (int)(user1.getName().compareTo(user2.getName()));
}
};
@Override
public String toString() {
return "Name: " + this.name + ", age: " + this.age;
}
}

  在上面的类中,我们写了两个匿名类实现了两个不同的compare()方法,可以按照两种不同的方式进行排序。
使用方法

1
2
3
ArrayList users = new ArrayList<>(); // 存储User对象的ArrayList
Collections.sort(users, User.ageComparator); // 按照年龄降序
Collections.sort(users, User.nameComparator); //按照姓名升序

  上面的代码调用了Collections.sort()的重载版本,这个版本接受两个参数:待排序ArrayList对象和Comparator对象。其中Comparator可以控制是升序还是降序,如果第一个参数大于第二个参数,compare()实现中返回正数,则是升序;返回负数,则是降序。我们也可以将User类中的匿名类剥离出来,作为一个单独的类,比如:
比较类,实现Comparator接口

1
2
3
4
5
6
7
8
9
10
import java.util.Comparator;
public class UserComparator implements Comparator {
@Override
public int compare(Object o1, Object o2) {
User user1 = (User)o1;
User user2 = (User)o2;
// 升序
return (user1.getAge() > uers2.getAge() ? 1 : (user1.getAge() == user2.getAge() ? 0 : -1));
}
}

使用方法

1
2
ArrayList users = new ArrayList();
Collections.sort(users, new UserComparator());

总结

  本文中我们看到了ArrayList排序的不同方法。一种是使用Comparable,另一种是Comparator。不能说一个接口比另一个更好,选择的接口取决于你需要实现的功能。你需要记住的就是:Comparable代表“我可以自己与另外一个对象比较”;Comparator代表“我可以比较两个不同的对象”。

参考:http://www.importnew.com/17211.html