前段时间看到一篇关于
Arrays.sort() 基本原理和使用的解读,正好之前自己也想总结一下关于Java中和排序相关的一些内容,不限于Arrays.sort() 、ArrayList.sort() 以及Comparator和Comparable接口。在本文中将介绍Arrays中各种重载的sort() ,以及解释如何使用Arrays.sort() 对任意类型的数据进行排序,这其中又涉及到Comparable接口和Comparator类的相关内容,最后在对比看一下ArrayList中的sort() 。
文章目录
- 1. 引入
- 2. Arrays.sort()
- 3. 自定义类型使用集合类中的sort()
- 4. ArrayList.sort()
- 5. 总结
- 6. 完整测试代码
1. 引入
如果现在有一个包含具体类型数据元素的数组,如何对数组中的元素进行排序呢?当然我们需要根据不同的数据类型确定具体的排序规则,如果是
在确定了数据元素数据类型和排序规则的前提下,接下来就需要编写排序逻辑。如果自己手造代码,可能工作量不是很大,但能不能利用Java中已有的东西来实现排序逻辑呢?当然!下面我们就来介绍一下如何使用
2. Arrays.sort()
Java.utils.Arrays是Java内置的一个方便操作数组的工具类,使用其中提供的众多静态方法可以快速简便的实现有关数组的大部分要求。
浅析Java中的Arrays
根据今天讨论的主题来说,我们只关注其中各种的

从图中的方框划分可以看出,全部的
-
针对于基本数据类型的方法
sort(xxx[] a) :其中xxx表示基本的数据类型,包括byte、char、double、float、int、long和short。每个数据类型又分别有两种实现方式:static void sort(xxx[] a) static void sort(xxx[] a, int fromIndex, int toIndex)
-
针对于引用类型的方法,其中的引用类型可以是String、Integer等包装类型,也可以是自定义数据类型,只不过自定义类型有进一步的要求,这个下面会说。同样有两种实现方式:
sort(Object[] a) sort(Object[] a, int fromIndex, int toIndex)
-
针对于泛型的方法:
static void sort(T[] a, int fromIndex, int toIndex, Comparator super T> c) static void sort(T[] a, Comparator super T> c)
因此,如果是上面提到的基本数据类型,可以直接使用
1 2 3 4 5 6 7 8 9 10 11 12 | import java.util.Arrays; public class ArraySort { public static void main(String[] args) { int[] arr1 = new int[]{2,10,5,8,3}; System.out.println(Arrays.toString(arr1)); // [2, 10, 5, 8, 3] Arrays.sort(arr1); System.out.println(Arrays.toString(arr1)); // [2, 3, 5, 8, 10] System.out.println("-----------------"); } } |
如果类似于String、Integer等对应于基本数据类型的包装类,那么可以使用第二类的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import java.util.ArrayList; import java.util.Arrays; public class ArraySort { public static void main(String[] args) { Integer[] arr2 = {2,10,5,8,3}; Arrays.sort(arr2); System.out.println(Arrays.toString(arr2)); // [2, 3, 5, 8, 10] System.out.println("-----------------"); String[] arr3 = new String[]{"James", "Forlogen", "Kobe"}; Arrays.sort(arr3); System.out.println(Arrays.toString(arr3)); // [Forlogen, James, Kobe] System.out.println("-----------------"); } } |
对于自定义的数据类型来说,参数列表中有
3. 自定义类型使用集合类中的sort()
对于自定义类型的数据来说,如果直接将保存数据的自定义类型数据的数组传入
1 | Exception in thread "main" java.lang.ClassCastException: collections.Student cannot be cast to java.lang.Comparable |
异常信息提示我们说,自定义的Student类无法转换为Comparable。至于其中涉及的泛型知识以及泛型中关于限定类型的东西,不了解的可以自行查阅下相关资料较好。这里就引出了对自定义类型数据使用
首先看一下定义的Student类为什么出现异常的原因,类的定义如下:
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 | public class Student{ private int age; private String name; public Student() { } public Student(int age, String name) { this.age = age; this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student{" + "age=" + age + ", name='" + name + '\'' + '}'; } } |
如果按照前面说明的方式来实现Comparable接口,并重写
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 | public class Student implements Comparable<Student>{ private int age; private String name; public Student() { } public Student(int age, String name) { this.age = age; this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student{" + "age=" + age + ", name='" + name + '\'' + '}'; } @Override public int compareTo(Student o) { // 降序为 o.getAge() - this.getAge() return this.getAge() - o.getAge(); } } |
然后我们再来看一下之前的代码能否正常进行排序,输出如下:
1 2 3 | Student{age=6, name='James'} Student{age=10, name='Forlgoen'} Student{age=20, name='Kobe'} |
从输出结果中可以看出,数组已经实现了按照age升序排列,说明方法是可行的。
另一种方式是实现自定义的Comparator,并重写其中的
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 | import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; public class ArraySort { public static void main(String[] args) { Student[] s = new Student[]{new Student(10, "Forlgoen"), new Student(6, "James"), new Student(20, "Kobe")}; Arrays.sort(s, new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { // 降序为 o2.getAge() - o1.getAge() return o1.getAge() - o2.getAge(); } }); for (Student student : s) { System.out.println(student); } System.out.println("-----------------"); /* Student{age=6, name='James'} Student{age=10, name='Forlgoen'} Student{age=20, name='Kobe'} */ } } |
输出结果和第一种方法是一样的,同样实现了按age进行升序排列。
既然包装类和自定义类同属于引用类型,那么包含包装类型数据的数组为什么能直接使用
1 2 3 | public final class Integer extends Number implements Comparable<Integer> { ... } |
我们继续在类中找一下看有没有
1 2 3 | public int compareTo(Integer anotherInteger) { return compare(this.value, anotherInteger.value); } |
而
1 2 3 | public static int compare(int x, int y) { return (x < y) ? -1 : ((x == y) ? 0 : 1); } |
从代码中可以看出,
然后我们再看一下上面使用的String的实现源码:
1 2 3 4 | public final class String implements java.io.Serializable, Comparable<String>, CharSequence { ... } |
可以看到它同样实现了 Comparable接口。然后我们再找一下重写的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public int compareTo(String anotherString) { int len1 = value.length; int len2 = anotherString.value.length; int lim = Math.min(len1, len2); char v1[] = value; char v2[] = anotherString.value; int k = 0; while (k < lim) { char c1 = v1[k]; char c2 = v2[k]; if (c1 != c2) { return c1 - c2; } k++; } return len1 - len2; } |
从实现代码中可以看出,它确实是按照字符串中字符的字典序进行的排序。其他的类型同理,可能
4. ArrayList.sort()
ArrayList中同样提供了关于排序的实现方法:
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 | import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; public class ArraySort { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); Collections.addAll(list, "James", "Forlogen", "Kobe"); list.sort(new Comparator<String>() { @Override public int compare(String o1, String o2) { return o1.length() - o2.length(); } }); list.forEach(k-> System.out.println(k)); System.out.println("-----------------"); Iterator<String> iter = list.iterator(); while (iter.hasNext()){ System.out.println(iter.next()); } System.out.println("-----------------"); /* Kobe James Forlogen */ } } |
从排序后的结果中可以看出,Comparator中的
5. 总结
从上面分析的内容中可以看出,如果对于除基本数据类型的数据使用
- 自定义类要实现Camparable接口,从重写其中的
CompareTo() ,重写的方法中定义自己的排序逻辑 - 实现自定义的Comparator,并重写其中的
Compare() ,同样需要在重写方法中定义排序的规则,然后将其作为方法的参数传入
另外,在代码实现中我们还随便复习了一下有关集合类的遍历的三种方法:
-
使用for-each进行遍历
1
2
3for (Student student : s) {
System.out.println(student);
} -
使用Iterator进行遍历
1
2
3
4Iterator<String> iter = list.iterator();
while (iter.hasNext()){
System.out.println(iter.next());
} -
使用
forEach() 进行遍历1list.forEach(k-> System.out.println(k));
6. 完整测试代码
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 66 67 68 69 70 71 72 73 74 75 76 77 | import java.util.*; public class ArraySort { public static void main(String[] args) { int[] arr1 = new int[]{2,10,5,8,3}; System.out.println(Arrays.toString(arr1)); // [2, 10, 5, 8, 3] Arrays.sort(arr1); System.out.println(Arrays.toString(arr1)); // [2, 3, 5, 8, 10] System.out.println("-----------------"); Integer[] arr2 = {2,10,5,8,3}; Arrays.sort(arr2); System.out.println(Arrays.toString(arr2)); // [2, 3, 5, 8, 10] System.out.println("-----------------"); String[] arr3 = new String[]{"James", "Forlogen", "Kobe"}; Arrays.sort(arr3); System.out.println(Arrays.toString(arr3)); // [Forlogen, James, Kobe] System.out.println("-----------------"); ArrayList<String> list = new ArrayList<>(); Collections.addAll(list, "James", "Forlogen", "Kobe"); list.sort(new Comparator<String>() { @Override public int compare(String o1, String o2) { return o1.length() - o2.length(); } }); list.forEach(k-> System.out.println(k)); System.out.println("-----------------"); Iterator<String> iter = list.iterator(); while (iter.hasNext()){ System.out.println(iter.next()); } System.out.println("-----------------"); /* Kobe James Forlogen */ Student[] s = new Student[]{new Student(10, "Forlgoen"), new Student(6, "James"), new Student(20, "Kobe")}; new ArrayList<Student>(Arrays.asList(s)).forEach(k-> System.out.println(k)); System.out.println("-----------------"); Arrays.sort(s); for (Student student : s) { System.out.println(student); } System.out.println("-----------------"); /* Exception in thread "main" java.lang.ClassCastException: collections.Student cannot be cast to java.lang.Comparable at java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:320) at java.util.ComparableTimSort.sort(ComparableTimSort.java:188) at java.util.Arrays.sort(Arrays.java:1246) at collections.ArraySort.main(ArraySort.java:35) */ Arrays.sort(s, new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { return o1.getAge() - o2.getAge(); } }); for (Student student : s) { System.out.println(student); } System.out.println("-----------------"); /* Student{age=6, name='James'} Student{age=10, name='Forlgoen'} Student{age=20, name='Kobe'} */ } } |