文章目录
- Java 中的自定义排序实现方法
- 1. 使用自定义比较器对数组进行排序
- 1.1 实现`Comparator`接口
- 1.2 使用`Arrays.sort()`方法
- 1.3 匿名内部类
- 1.4 代码结果
- 2. 使用自定义比较器对集合进行排序
- 2.1 实现`Comparable`接口
- 2.2 使用`Collections.sort()`方法
- 2.3 使用Lambda表达式
- 2.4 代码结果
- 比较器的排序规则
- 返回值规则
- 举例
- 注意点
- 比较两个接口
- `Comparable` 接口
- `Comparator` 接口
- 总结
- 比较两个方法
- Arrays.Sort ()
- Collections.Sort ()
- 关键区别
Java 中的自定义排序实现方法
在Java中,排序是经常需要用到的操作,Java提供了两种通用的排序方法:
- Arrays.sort()方法: 适用于基本类型数组和对象数组。
- Collections.sort()方法: 适用于实现了
Comparable
接口的集合。
但是有时我们想自定义排序的规则,就要使用这两种方法的重载版本,传入自定义的比较器(Comparator)对象。
1. 使用自定义比较器对数组进行排序
1.1 实现Comparator
接口
要自定义数组的排序规则,首先需要创建一个类,实现Comparator
接口。该接口只有一个方法:
int compare(T o1, T o2);
该方法用于比较两个元素,并返回一个整数:
- 如果
o1
小于o2
,则返回-1。 - 如果
o1
等于o2
,则返回0。 - 如果
o1
大于o2
,则返回1。
例如,要按照字符串的长度对字符串数组进行排序,可以定义如下比较器:
class StringLengthComparator implements Comparator<String> {@Overridepublic int compare(String s1, String s2) {return s1.length() - s2.length();}
}
1.2 使用Arrays.sort()
方法
有了自定义比较器之后,就可以使用Arrays.sort()
方法对数组进行排序。该方法的重载版本接受一个数组和一个比较器对象作为参数:
Arrays.sort(array, comparator);
例如,要按照字符串的长度对字符串数组strArray
进行排序,可以使用如下代码:
String[] strArray = {"abc", "12345", "abcdef"};
StringLengthComparator comparator = new StringLengthComparator();
Arrays.sort(strArray, comparator);
1.3 匿名内部类
如果只是为了简单的排序需求,可以使用匿名内部类来实现Comparator
接口。例如,要按照字符串的自然顺序对字符串数组进行排序,可以使用如下代码:
Arrays.sort(strArray, new Comparator<String>() {@Overridepublic int compare(String s1, String s2) {return s1.compareTo(s2);}
});
1.4 代码结果
class StringLengthComparator implements Comparator<String> {@Overridepublic int compare(String s1, String s2) {return s1.length() - s2.length(); // to sort in ascending order}}public static void compareStrings2() {String[] strArray = { "12345", "abc", "abcdef" };StringLengthComparator comparator = new StringLengthComparator();Arrays.sort(strArray, comparator);System.out.println(Arrays.toString(strArray));// Output: [abc, 12345, abcdef]/** 解释:`StringLengthComparator`类实现了`Comparator`接口* 并重写了`compare()`方法,以便根据字符串的长度进行比较。* `Arrays.sort()`方法用于根据* 自定义比较器对字符串数组进行排序。* https://blog.csdn.net/weixin_43359009?spm=1011.2266.3001.5343*/Arrays.sort(strArray, new Comparator<String>() {@Overridepublic int compare(String s1, String s2) {return -(s1.length() - s2.length());}});System.out.println(Arrays.toString(strArray));// Output: [abcdef, 12345, abc]/** 解释:`Arrays.sort()`方法用于根据自定义比较器对字符串数组进行排序。* 在这种情况下,比较器是一个匿名类,它重写了`compare()`方法以便根据字符串的长度进行比较。* 返回负值,可以实现降序排序。*/}
2. 使用自定义比较器对集合进行排序
2.1 实现Comparable
接口
要自定义集合的排序规则,首先需要使集合中的元素类实现Comparable
接口。该接口只有一个方法:
int compareTo(T o);
该方法用于比较当前对象和另一个对象的相对大小,并返回一个整数:
- 如果当前对象小于另一个对象,则返回-1。
- 如果当前对象等于另一个对象,则返回0。
- 如果当前对象大于另一个对象,则返回1。
例如,要按照学生的分数对学生对象进行排序,可以定义如下学生类:
class Student implements Comparable<Student> {private String name;private int score;public Student(String name, int score) {this.name = name;this.score = score;}@Overridepublic int compareTo(Student other) {return this.score - other.score;}
}
2.2 使用Collections.sort()
方法
有了实现了Comparable
接口的元素类之后,就可以使用Collections.sort()
方法对集合进行排序。该方法的重载版本接受一个集合作为参数:
Collections.sort(collection);
例如,要按照学生的成绩对学生集合studentList
进行排序,可以使用如下代码:
List<Student> studentList = new ArrayList<>();
studentList.add(new Student("Alice", 90));
studentList.add(new Student("Bob", 80));
studentList.add(new Student("Charlie", 70));
Collections.sort(studentList);
2.3 使用Lambda表达式
在Java 8及更高版本中,可以使用Lambda表达式来代替匿名内部类,使代码更加简洁。例如,要按照学生的成绩对学生集合studentList
进行排序,可以使用如下代码:
studentList.sort((s1, s2) -> s1.getScore() - s2.getScore());
2.4 代码结果
class Student implements Comparable<Student> {public String name;public int score;public Student(String name, int score) {this.name = name;this.score = score;}@Overridepublic int compareTo(Student other) {return this.score - other.score;}}public static void compareObjects() {List<Student> studentList = new ArrayList<>();studentList.add(new Student("Alice", 90));studentList.add(new Student("Bob", 80));studentList.add(new Student("Charlie", 70));Collections.sort(studentList);for (Student student : studentList) {System.out.println(student.name + ": " + student.score);}// Output:// Charlie: 70// Bob: 80// Alice: 90/** 解释:`Student`类实现了`Comparable`接口并重写了`compareTo()`方法,* 以便根据学生的分数进行比较。`Collections.sort()`方法用于根据`compareTo()`方法定义的自然顺序对学生数组进行排序。* https://blog.csdn.net/weixin_43359009?spm=1011.2266.3001.5343*/}
比较器的排序规则
在 Java 中,无论是实现 Comparable
接口的 compareTo
方法,还是创建 Comparator
接口的实例时实现的 compare
方法,其返回值都遵循一个通用的规则,以决定排序的顺序。
返回值规则
- 负整数: 如果方法返回负整数,表示第一个参数(
compareTo
中的this
或compare
中的o1
)应该排在第二个参数(compareTo
中的o
或compare
中的o2
)之前。 - 零: 如果方法返回零,表示这两个参数在排序时被视为相等。
- 正整数: 如果方法返回正整数,表示第一个参数应该排在第二个参数之后。
举例
其实上文中的代码已经有过示例了,但是这里仍给出一个简单的示例并解释。
假设有一个 Person
类,其中包含 age
和 name
两个字段,想要根据 age
对 Person
对象进行排序。
public class Person {int age;String name;// ...... https://blog.csdn.net/weixin_43359009?spm=1011.2266.3001.5343
}Comparator<Person> byAge = new Comparator<Person>() {@Overridepublic int compare(Person o1, Person o2) {return o1.age - o2.age;}
};
在这个比较器中,如果 o1
的年龄小于 o2
的年龄,o1.age - o2.age
将返回一个负值,表示 o1
应该排在 o2
之前,从而实现了升序排序。
反之,如果 o1
的年龄大于 o2
的年龄,将返回一个正值,表示 o1
应该排在 o2
之后。
如果两者年龄相同,返回零,表示两者在排序时被视为相等。
注意点
- 当实现
Comparator
或Comparable
时,返回值不必严格限制为-1、0 或 1。任何负整数值都表示“小于”,任何正整数值都表示“大于”。 - 在实现比较逻辑时,特别是涉及到数值差异计算的场景(如上述例子中的
o1.age - o2.age
),要注意数值溢出的问题。对于大整数的比较,推荐使用Integer.compare(x, y)
或Long.compare(x, y)
等静态方法,这些方法内部已经处理了溢出问题。
比较两个接口
Comparable
和 Comparator
都是 Java 中用来实现对象排序的接口,它们在用法和设计目的上有一些关键的不同之处:
Comparable
接口
- 包路径:
java.lang.Comparable
- 用途: 当我们想要定义一个类的自然排序时使用。例如,一个
Person
类可能按照年龄或姓名自然排序。 - 方法: 该接口只包含一个方法
compareTo(T o)
,任何实现了Comparable
接口的类都必须实现这个方法。 - 实现方式: 类内部比较机制,即一个对象自己知道如何与另一个对象进行比较。
- 使用场景: 适用于你拥有源代码的类,并且你希望该类的对象有一个默认的排序方式。
Comparator
接口
- 包路径:
java.util.Comparator
- 用途: 当我们需要定义多种排序方式,或者我们无法修改要排序的类的源代码时使用。例如,如果
Person
类是一个第三方库的一部分,我们无法为其实现Comparable
接口,但我们仍然想要根据年龄或姓名对Person
对象进行排序。 - 方法: 该接口包含一个方法
compare(T o1, T o2)
,用于比较两个对象。 - 实现方式: 类外部比较机制,即我们创建一个单独的比较器(Comparator)来定义两个对象如何比较。
- 使用场景: 当你需要对某个类的对象进行排序,但是你不能修改原始类,或者你需要对同一个类的对象以不同的方式进行排序时。
总结
- 修改源代码: 如果可以修改类的源代码,并且该类有一个自然的排序顺序,使用
Comparable
。 - 多种排序方式或无法修改源代码: 如果你需要多种排序方式,或者你无法修改要排序的类,使用
Comparator
。
使用 Comparable
和 Comparator
可以让你的对象支持排序操作,如使用 Collections.sort()
或 Arrays.sort()
方法进行排序。选择哪一个取决于你的具体需求和上述提到的考量。
比较两个方法
Arrays.sort()
和 Collections.sort()
都是 Java 中用于排序的常用方法,但它们之间存在一些关键的区别,主要体现在它们的使用场景和内部工作机制上。
Arrays.Sort ()
- 定义位置:
java.util.Arrays
类中。 - 使用场景: 用于对数组进行排序。可以对原始数据类型数组(如
int[]
,double[]
等)和对象数组(如String[]
,Integer[]
等)进行排序。 - 工作原理:
Arrays.sort()
方法根据数组的数据类型采用不同的排序算法。对于原始数据类型数组,通常采用快速排序算法;而对于对象数组,则使用改进的归并排序(TimSort)。 - 重载版本: 提供了多个重载方法,允许你对整个数组或指定范围内的元素进行排序。也可以接受一个
Comparator
,用于对象数组的定制排序。
Collections.Sort ()
- 定义位置:
java.util.Collections
类中。 - 使用场景: 专门用于对实现了
List
接口的集合进行排序,比如ArrayList
,LinkedList
等。 - 工作原理:
Collections.sort()
内部也是使用改进的归并排序算法(TimSort)来对列表进行排序。 - 重载版本: 提供了两种形式的
sort
方法。一种是只接受List
对象,按照元素的自然顺序进行排序;另一种是除了List
对象外,还接受一个Comparator
参数,用于定制排序规则。
关键区别
- 应用类型:
Arrays.sort()
用于数组,而Collections.sort()
用于List
接口的集合。 - 排序算法: 对于原始类型数组,
Arrays.sort()
可能使用快速排序;对于对象类型数组和Collections.sort()
,则使用 TimSort 算法。 - 灵活性:
Collections.sort()
只能用于List
集合,而Arrays.sort()
可以对任何类型的数组进行排序,包括原始数据类型和对象数组。 - 定制排序: 两者都支持定制排序,允许通过传递
Comparator
实现特定的排序逻辑。
在选择使用 Arrays.sort()
还是 Collections.sort()
时,主要考虑要排序的数据类型(数组还是 List
集合)。对于集合框架中的列表,推荐使用 Collections.sort()
。对于数组类型的数据,则必须使用 Arrays.sort()
。