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方法(代价有点大的感觉)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值