[Java SE] Java 排序接口: `Comparable` / `Comparator`
概述:Java 排序接口: Comparable / Comparator
- 在 Java 中,排序功能主要通过
Comparable接口和Comparator接口来实现。
这两个接口在功能和使用场景上有一些区别,以下是它们的详细比较:
java.lang.Comparable 接口
-
定义:
Comparable是一个内置的 Java 接口,定义在java.lang包中。- 它允许一个类实现一个自然排序(natural ordering),即根据对象的某个属性进行排序。
-
方法:
int compareTo(T o):比较当前对象与参数对象的大小。返回值:- 负数:当前对象小于参数对象。
- 零:当前对象等于参数对象。
- 正数:当前对象大于参数对象。
-
使用场景:
- 当类的实例需要按照某种固定的、自然的顺序排序时,可以实现
Comparable接口。 - 例如,
String类实现了Comparable接口,按照字典顺序排序;Integer类实现了Comparable接口,按照数值大小排序。
- 当类的实例需要按照某种固定的、自然的顺序排序时,可以实现
-
优点:
- 提供了自然排序的方式,使得类的实例在默认情况下可以被排序。
- 可以直接使用
Arrays.sort()或Collections.sort()对实现了Comparable接口的类的实例进行排序。
-
缺点:
- 一个类只能实现一种自然排序方式。如果需要多种排序方式,则需要额外的机制。
java.util.Comparator 接口
- 定义:
Comparator是一个函数式接口,定义在java.util包中。- 它允许定义一个外部的比较器,用于对类的实例进行排序。
- 方法:
int compare(T o1, T o2):比较两个对象的大小。返回值:- 负数:
o1小于o2。 - 零:
o1等于o2。 - 正数:
o1大于o2。
- 负数:
boolean equals(Object obj):用于比较两个比较器是否相等。
- 使用场景:
- 当需要对类的实例进行多种排序方式时,可以定义多个
Comparator。 - 例如,对于一个
Person类,可以定义一个按年龄排序的Comparator和一个按姓名排序的Comparator。
- 当需要对类的实例进行多种排序方式时,可以定义多个
- 优点:
- 提供了灵活的排序方式,可以定义多个比较器来满足不同的排序需求。
- 可以在不修改类代码的情况下,为类的实例提供多种排序方式。
- 缺点:
- 需要额外定义比较器,增加了代码的复杂性。
- 使用时需要显式指定比较器,不如
Comparable接口的自然排序直观。
比较与选择
- 单一排序需求:
- 如果类的实例只需要一种固定的排序方式,建议实现
Comparable接口。 - 例如,
Integer类只需要按照数值大小排序,因此实现Comparable接口是合适的。
- 如果类的实例只需要一种固定的排序方式,建议实现
- 多种排序需求:
- 如果类的实例需要多种排序方式,建议使用
Comparator接口。 - 例如,
Person类可能需要按年龄排序,也可能需要按姓名排序,此时可以定义多个Comparator。
- 如果类的实例需要多种排序方式,建议使用
- 灵活性与扩展性:
Comparator接口提供了更高的灵活性和扩展性,适合复杂的排序需求。Comparable接口则更简单、更直观,适合单一的排序需求。
代码示例
实现 Comparable 接口
import java.util.*;
class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(Person other) {
return this.age - other.age; // 按年龄排序
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
public class Main {
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add(new Person("Alice", 30));
people.add(new Person("Bob", 25));
people.add(new Person("Charlie", 35));
Collections.sort(people); // 使用 Comparable 接口排序
System.out.println(people);
}
}
使用 Comparator 接口
import java.util.*;
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
public class Main {
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add(new Person("Alice", 30));
people.add(new Person("Bob", 25));
people.add(new Person("Charlie", 35));
// 按年龄排序
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge() - o2.getAge();
}
});
System.out.println(people);
// 按姓名排序
people.sort((p1, p2) -> p1.getName().compareTo(p2.getName()));
System.out.println(people);
}
}
使用 Comparator 接口对List元素排序(项目案例)
DataElementSubElementNoComparator
package com.xxx.sdk.java.someip.parse.sort;
import com.xxx.sdk.pojo.someip.entity.DataElementInfo;
import java.util.Comparator;
/**
* DataElementInfo SubElementNo 字段排序器
* @note
* 1. Comparator 是一个策略接口,用于定义自定义排序规则;
* 2. 你可以在不修改类本身的情况下,通过实现 Comparator 来定义多个排序规则
* @reference-doc
* [1] Java 排序神器:Comparable 和 Comparator 该怎么选? - Zhihu - https://zhuanlan.zhihu.com/p/17041375356
*/
public class DataElementSubElementNoComparator implements Comparator<DataElementInfo> {
/**
* 根据 SubElementNo 升序排序
* @param o1 the first object to be compared.
* @param o2 the second object to be compared.
* @return
*/
@Override
public int compare(DataElementInfo o1, DataElementInfo o2) {
if(o1.getSubElementNo() > o2.getSubElementNo()){
return 1;
} else if(o1.getSubElementNo() < o2.getSubElementNo()){
return -1;
}
return 0;
}
}
排序器的使用
...
public static DataElementDefinitions convertToDataElementDefinitions(Map<String, List<DataElementInfo>> dataElementInfoListMap, Boolean structSorted){
Boolean isRecursiveNode = true;//是否完全递归, 以设置父节点和子节点
//DataElementDefinitions dataElementDefinitions = parseMatrixAsFlatMapDataElementDefinitions(someIpMatrixFilePath);
if(!structSorted){//结构体元素是否已升序排序(否则,影响结构体的解析顺序)
dataElementInfoListMap.entrySet().stream().forEach(dataElementInfoLisEntry -> {
List<DataElementInfo> dataElementInfoList = dataElementInfoLisEntry.getValue();
if(dataElementInfoList != null && dataElementInfoList.size() > 1){
dataElementInfoList.sort(new DataElementSubElementNoComparator());//←←←←←←←←←←
}
});
}
DataElementDefinitions dataElementDefinitions = convertToFlatMapDataElementDefinitions(dataElementInfoListMap);
if(isRecursiveNode){
dataElementDefinitions.entrySet().stream().forEach( dataElementDefinitionEntry -> {
String parameterName = dataElementDefinitionEntry.getKey();
DataElementDefinition dataElementDefinition = dataElementDefinitionEntry.getValue();
recursiveNodeDataElementDefinitions( dataElementDefinition, dataElementDefinitions );
});
}
return dataElementDefinitions;
}
...
用 Collections.reverseOrder() 进行逆序
public class Test5 {
public static void main(String[] args) {
Integer[] arr = {9, 8, 7, 2, 3, 4, 1, 0, 6, 5};
Arrays.sort(arr, Collections.reverseOrder());
for(int x:arr){
System.out.print(x); //print: 9876543210
}
}
}
基于 List.sort(Comparator 接口) 实现对 List 对象自身的元素进行排序
java.util.List#sort
void sort(Comparator<? super E> var1)
- demo
public class ListSortTest {
private final static Logger log = LoggerFactory.getLogger(ListSortTest.class);
@Test
public void sortTest(){
List<ParsedCycleSequenceVo> cycleSequences = new ArrayList<>();
ParsedCycleSequenceVo cycleCanSequence1 = new ParsedCycleSequenceVo();cycleSequence1.setCollectTs( 1L );
ParsedCycleSequenceVo cycleCanSequence2 = new ParsedCycleSequenceVo();cycleSequence2.setCollectTs( 3L );
ParsedCycleSequenceVo cycleCanSequence3 = new ParsedCycleSequenceVo();cycleSequence3.setCollectTs( 2L );
cycleSequences.add( cycleCanSequence1 );
cycleSequences.add( cycleCanSequence2 );
cycleSequences.add( cycleCanSequence3 );
log.info("cycleSequences:{}", JSON.toJSONString( cycleSequences ));//[{"collect_ts":1},{"collect_ts":3},{"collect_ts":2}]
cycleSequences.sort( new Comparator<ParsedCycleSequenceVo>() {
@Override
public int compare(ParsedCycleSequenceVo o1, ParsedCycleSequenceVo o2) {
return o1.getCollectTs().compareTo( o2.getCollectTs() );//升序
}
});
log.info("cycleSequences:{}", JSON.toJSONString( cycleSequences ));//[{"collect_ts":1},{"collect_ts":2},{"collect_ts":3}]
}
}
X 参考文献
本文作者:
千千寰宇
本文链接: https://www.cnblogs.com/johnnyzen
关于博文:评论和私信会在第一时间回复,或直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
日常交流:大数据与软件开发-QQ交流群: 774386015 【入群二维码】参见左下角。您的支持、鼓励是博主技术写作的重要动力!
本文链接: https://www.cnblogs.com/johnnyzen
关于博文:评论和私信会在第一时间回复,或直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
日常交流:大数据与软件开发-QQ交流群: 774386015 【入群二维码】参见左下角。您的支持、鼓励是博主技术写作的重要动力!

浙公网安备 33010602011771号