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()
进行排序了。
使用Comparable对ArrayList排序是一种常用的方法。但是你必须知道有某些限制。你想要排序的对象的类必须实现Comparable并覆写compareTo()
方法。这意味着你将只能基于一种方式来比较对象。如果有时候要求你按照姓名排序,有时候又要求你按照年龄排序怎么办?Comparable就不是解决的方法了。另外,比较逻辑是需要进行比较的对象的类的一部分,它消除了比较逻辑可复用性的可能。Java通过使用java.util包提供的Comparator接口解决上述的比较需求。
使用Comparator排序ArrayList
Comparator接口与Comparable接口相似也提供了一个单一的比较方法叫作compare()
。然而,与Comparable的compareTo()
方法不同的是,这个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<>(); 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