Java中Comparable和Comparator的总结

1 Comparable 接口

Comparable接口是排序接口,只能是类来实现Comparable接口。既然实现Comparable接口的类支持排序,那么“ 实现了Comparable接口的类的对象的List列表(或数组)”,可以通过Collections.sort(或Arrays.sort)进行排序。

“实现Comparable接口的类的对象”可以用作“有序映射(如TreeMap)”中的键或“有序集合(TreeSet)”中的元素,而不需要指定比较器。

Comparable接口定义

public interface Comparable<T> {
    public int compareTo(T o);
}
  • compareTo() 方法用于两种方式的比较:
    • 字符串与对象进行比较
    • 按字典顺序比较两个字符串
    • 如果想进行两个数字之间的比较,必须是两个包装类之间的比较可以是一个 Byte, Double, Integer, Float, Long 或 Short 类型的参数。

示例代码

  1. Person类定义
/**
 * Person类实现Comparable接口,使该类具有排序的功能
 * @author jie
 * @date 2021-07-06 10:44
 */
public class Person implements Comparable<Person>{
    private int age;
    private String name;

    /**
     * 实现 “Comparable<String>” 的接口,即重写compareTo<T t>函数。
     * 这里是通过“person的名字”进行比较的
     */
    @Override
    public int compareTo(Person person) {
        return name.compareTo(person.name);
    }
    
    ...
}

注意:

  • 实现的Comparable接口的泛型必须是待排序的类
  • compareTo()传入的参数是待排序类的对象
  • compareTo() 不能直接对int类型的age进行排序,如果想使用compareTo()进行排序,必须将int类型的age转成Integer类型的age
  1. 在main()中,我们创建了Person的List数组(list)
List<Person> list = new ArrayList<>();
// 添加对象到ArrayList中
list.add(new Person("ccc", 20));
list.add(new Person("AAA", 30));
list.add(new Person("bbb", 10));
list.add(new Person("ddd", 40));
  1. 打印list里的全部元素
// 打印list的原始序列
System.out.printf("Original sort, list:%s\n", list);

/**
运行结果:
Original sort, list:[Person{age=20, name='ccc'}, Person{age=30, name='AAA'}, Person{age=10, name='bbb'}, Person{age=40, name='ddd'}]
 */
  1. 通过Collections的sort()函数,对list进行排序

正如前面所说,实现了Comparable接口的类的对象的List列表(或数组)”,可以通过Collections.sort(或Arrays.sort)进行排序。

由于Person实现了Comparable接口,因此通过sort()排序时,会根据Person支持的排序方式,即 compareTo(Person person) 所定义的规则进行排序。如下:

// 对list进行排序
// 这里会根据“Person实现的Comparable<String>接口”进行排序,即会根据“name”进行排序
Collections.sort(list);
System.out.printf("Name sort, list:%s\n", list);

/**
运行结果:
Name sort, list:[Person{age=30, name='AAA'}, Person{age=10, name='bbb'}, Person{age=20, name='ccc'}, Person{age=40, name='ddd'}]
 */

2 Comparator 接口

Comparator 是比较器接口

我们若需要控制某个类的次序,而该类本身不支持排序(即没有实现Comparable接口);那么,我们可以建立一个“该类的比较器”来进行排序。这个“比较器”只需要实现Comparator接口即可。

也就是说,我们可以通过“实现Comparator类来新建一个比较器”,然后通过该比较器对类进行排序。

Comparator接口定义

public interface Comparator<T> {

    int compare(T o1, T o2);

    boolean equals(Object obj);
}

示例代码

  1. Person类定义

① 实现Comparable接口

/**
 * 实现Comparable接口,使该类具有排序的功能
 * @author jie
 * @date 2021-07-06 14:49
 */
public class PersonComparable implements Comparable<PersonComparable> {
    int age;
    String name;

    /**
     * 实现 “Comparable<String>” 的接口,即重写compareTo<T t>函数。
     * 这里是通过“personComparable的name属性”进行比较的
     */
    @Override
    public int compareTo(PersonComparable personComparable) {
        return name.compareTo(personComparable.name);
    }
    
    ...
        
}

② 未实现Comparable接口

public class Person implements Comparable<Person>{
    private int age;
    private String name;
}
  1. 在main()中,创建Person的List数组(list)

① 实现了Comparable接口

List<PersonComparable> list = new ArrayList<>();

// 添加对象到ArrayList中
list.add(new PersonComparable("ccc", 20));
list.add(new PersonComparable("AAA", 30));
list.add(new PersonComparable("bbb", 10));
list.add(new PersonComparable("ddd", 40));

② 未实现Comparable接口

List<Person> list = new ArrayList<>();
// 添加对象到ArrayList中
list.add(new Person("ccc", 20));
list.add(new Person("AAA", 30));
list.add(new Person("bbb", 10));
list.add(new Person("ddd", 40));
  1. 利用Comparator比较器对列表进行排序

Collections.sort()定义

// 使用lambda表达式实现Comparator接口,即自定义排序规则
public static <T> void sort(List<T> list, Comparator<? super T> c) {
    list.sort(c);
}

Comparator接口里的int compare(T o1, T o2)

  • 当比较的两个参数是对象时,需要对象实现Comparable接口

  • 当比较的两个参数是字符串时,需要使用compareTo()来比较

  • 当比较的两个参数是数值时,直接使用减号 -来比较

比较的两个参数是对象

① 实现了Comparable接口

Collections.sort(list, (o1, o2)->{
    // 这里o1, o2表示的是list列表里单个元素表示的对象,即PersonComparable类的对象
    return o1.compareTo(o2);
});

System.out.println("排序后:"+list);

/**
运行结果:
排序后:[PersonComparable{age=30, name='AAA'}, PersonComparable{age=10, name='bbb'}, PersonComparable{age=20, name='ccc'}, PersonComparable{age=40, name='ddd'}]
 */

等价于 Collections.sort(list),正好对应了前面所说的。

② 未实现Comparable接口

程序直接报错,编译都过不了。

总结:

  • 实现了Comparable接口的类,可以通过Comparator比较器来进行排序,排序的规则是类中重写的compareTo()方法中自定义的(这里是按照name排序)
  • 未实现Comparable接口的类,无法通过Comparator比较器来进行排序

比较的两个参数是字符串或包装类

① 未实现Comparable接口

Collections.sort(list, (o1, o2)->{
    // 根据name排序,这里o1, o2表示的是list列表里单个元素表示的对象
    return o1.name.compareTo(o2.name);
});

System.out.println("name排序后:" + list);
/**
运行结果:
name排序后:[Person{age=30, name='AAA'}, Person{age=10, name='bbb'}, Person{age=20, name='ccc'}, Person{age=40, name='ddd'}]
 */

② 实现Comparable接口

和未实现Comparable接口的结果一样,能按照name正常排序。

比较的两个参数是数值

① 未实现Comparable接口

Collections.sort(list, (o1, o2)->{
    // 根据age排序
    return o1.age - o2.age;
});

System.out.println("age排序后:" + list);
/**
运行结果:
age排序后:[Person{age=10, name='bbb'}, Person{age=20, name='ccc'}, Person{age=30, name='AAA'}, Person{age=40, name='ddd'}]
 */

② 实现Comparable接口

Collections.sort(list, (o1, o2)->{
    return o1.age - o2.age;
});

System.out.println("排序后:"+list);
/**
运行结果:
排序后:[PersonComparable{age=10, name='bbb'}, PersonComparable{age=20, name='ccc'}, PersonComparable{age=30, name='AAA'}, PersonComparable{age=40, name='ddd'}]
 */

会覆盖Comparable接口中compareTo()方法中自定义的排序规则, 和未实现Comparable接口的结果一样,能按照age正常排序。

数组Arrays工具类同理

Arrays.sort(persons, (o1, o2)->{
    // 根据name排序,这里o1, o2表示的是list列表里单个元素表示的对象
    return o1.name.compareTo(o2.name);
});


Arrays.sort(persons, (o1, o2)->{
    // 根据age排序
    return o1.age - o2.age;
});

3 总结

Comparable是排序接口;若一个类实现了Comparable接口,就意味着“该类支持排序”。
而Comparator是比较器;我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序

我们不难发现:Comparable相当于“内部比较器”,而Comparator相当于“外部比较器”。

  • Comparable接口,只是为了将类可以按照自定义的排序规则排序,在重写的compareTo()方法中,字符串类型的参数可以直接比较,而数值类型的必须使用对应的包装类进行比较
  • 实现了Comparable接口的类的对象的List列表(或数组)”,可以通过Collections.sort(或Arrays.sort)进行排序。相当于是Comparator接口中重写的compare()方法,比较的是两个对象。
  • Comparator接口中重写的compare()方法,当比较的两个参数是字符串或包装类时,需要使用compareTo()来比较
  • Comparator接口中重写的compare()方法,当比较的两个参数是数值时,直接使用减号 -来比较

参考资料:

  1. Java 中 Comparable 和 Comparator 比较

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值