comparable 和 comparator

comparable 和 comparator

一、对java对象进行排序

  1. 需要对java对象进行排序,一般使用Collections.sort(list);。 此时对于比较的对象,

    1. 要么实现Comparable接口
    2. 在排序时,指定对应的比较器 public static <T> void sort(List<T> list, Comparator<? super T> c)
  2. 演示如下:

    public static void main(String[] args) {
        test01();
    }
    
    private static void test01() {
        Person p1 = new Person("a", 3);
        Person p2 = new Person("b", 1);
        Person p3 = new Person("c", 4);
        Person p4 = new Person("d", 2);
        Person p5 = new Person("e", 5);
    
        List<Person> personList = new ArrayList<>();
        personList.add(p3);
        personList.add(p1);
        personList.add(p5);
        personList.add(p2);
        personList.add(p4);
    
        showPersonInfo(personList);
    
        // 默认排序
        System.out.println("默认排序");
        Collections.sort(personList);
        showPersonInfo(personList);
    
        // 自定义排序
        System.out.println("自定义排序");
        Collections.sort(personList, new Comparator<Person>() {
    
            @Override
            public int compare(Person o1, Person o2) {
                int age1 = o1.getAge();
                int age2 = o2.getAge();
                return age1 - age2;
            }
        });
        showPersonInfo(personList);
    }
    
    private static void showPersonInfo(List<Person> personList) {
        for (Person person : personList) {
            System.out.println(person);
        }
    
    }
Person.java
   public class Person implements Comparable<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 int compareTo(Person o) {
        return this.name.compareTo(o.getName());
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }

}

二、在实现comparable接口时,建议也实现equals方法

在实现comparable接口时,实现了compareTo方法,同时也建议实现equals方法。 此时使用findbugs工具扫描,会要求两个方法在判断上保持一致

摘录:

Eq: Class defines compareTo(...) and uses Object.equals() (EQ_COMPARETO_USE_OBJECT_EQUALS)

This class defines a compareTo(...) method but inherits its equals() method from java.lang.Object. Generally, the value of compareTo should return zero if and only if equals returns true. If this is violated, weird and unpredictable failures will occur in classes such as PriorityQueue. In Java 5 the PriorityQueue.remove method uses the compareTo method, while in Java 6 it uses the equals method.

From the JavaDoc for the compareTo method in the Comparable interface:

It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y)). Generally speaking, any class that implements the Comparable interface and violates this condition should clearly indicate this fact. The recommended language is "Note: this class has a natural ordering that is inconsistent with equals."

另外,还有一种解释:

当我们需要判断集合中是否包含某个元素时,可以使用下面两种方法,分别是 list.indexOf 和 Collections.binarySearch方法,然而前者判断使用equals方法,而后者使用compareTo方法。

  1. 口说无凭,看源码:
  2. list.indexOf方法

    .
  3. Collections.binarySearch方法 

  4. 代码演示如下:

    Person.java
public class Person implements Comparable<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 int compareTo(Person o) {
        return this.name.compareTo(o.getName());
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }

    // 此处为了测试,故意让compareTo方法+equals方法不一致
    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Person) {
            Person another = (Person) obj;
            int diff = this.age - another.getAge();
            return diff > 0;
        }
        return false;
    }

}
WhyEquals.java
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class WhyEquals {

    public static void main(String[] args) {
        List<Person> personList = new ArrayList<>();
        personList.add(new Person("alice", 40));
        personList.add(new Person("bob", 30));
        personList.add(new Person("green", 20));

        // 我们要查找的对象
        Person target = new Person("bob", 0);

        // 第一种方法:List.indexOf ==> 用的equals方法
        int index = personList.indexOf(target);
        System.out.println(index);
        // -1

        // 第二种方法:Collections.binarySearch方法 ==> 用的是
        // 但是binarySearch要求集合是有序的
        Collections.sort(personList);
        index = Collections.binarySearch(personList, target);
        System.out.println(index);
        // 1
    }
}
  1. 结果解释:
    • 由于indexOf使用equals方法 ==> 根据age判断 ==> 所以找不到;
    • 由于Collections.binarySearch使用compareTo方法 ==>根据name判断 ==> 找到name相同的元素。

三、总结:

  • 优先考虑使用comparator方法(灵活)
  • 如果对象的比较是唯一的,建议实现comparable接口,同时覆写equals+hashcode方法(代价有点大的感觉)

`Comparable` `Comparator` 都是用来对对象排序的接口,但在使用场景设计意图上有所不同。 ### 1. **Comparable 接口** `Comparable<T>` 是 Java 中的一个泛型接口,它允许你在定义类的时候指定该类的对象应该如何比较大小。通常用于表示自然顺序(natural ordering),例如数字从小到大、字符串按字典序等。 #### 特点: - 类本身需要实现这个接口,并提供 `compareTo(T o)` 方法的具体实现。 - 只能有一种比较规则,即只能有一个“自然”排序方式。 - 如果某个类实现了 `Comparable`,那么它的实例可以直接通过 `Collections.sort()` 或 `Arrays.sort()` 进行排序。 **示例:** ```java public 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 Integer.compare(this.age, other.age); // 按年龄升序排列 } } ``` --- ### 2. **Comparator 接口** `Comparator<T>` 同样是一个泛型接口,但它不是由类直接实现的,而是作为外部策略模式来使用的。你可以创建一个独立的 Comparator 实现类或匿名内部类,甚至可以使用 lambda 表达式,在运行时动态地传递给排序算法。 #### 特点: - 提供了更灵活的比较逻辑,可以在不修改原有类的情况下为同一个类提供多种排序方式。 - 可以有多个不同的 `Comparator` 来处理同一种类型的对象的不同排序需求。 - 经常与 `TreeSet`, `PriorityQueue` 等数据结构一起使用,也可以传入 `sort()` 方法中作为参数。 **示例:** ```java import java.util.*; List<Person> people = new ArrayList<>(); // 添加一些Person对象... // 使用Comparator按名字排序 people.sort(Comparator.comparing(person -> person.getName())); // 或者按年龄降序排序 people.sort((p1, p2) -> Integer.compare(p2.getAge(), p1.getAge())); ``` --- ### 总结 - **Comparable**:适合于对象自带的一种天然有序关系,且这种顺序通常是唯一的; - **Comparator**:适用于当你想要在同一组对象上有多种不同的排序方式,或者不想改变原始类的设计时; 选择哪一个取决于具体的业务需求以及你希望如何组织代码。 --
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值