Comparable接口实现(当需要对某个对象进行排序时)

Comparable接口实现(当需要对某个对象进行排序时)

如标题所说,当你需要对某个自定义类进行排序时,你就需要实现Comparable接口。
反过来说,当一个类实现了Comparable接口时,就表明它的实例具有内在的排序关系。

Java平台类库中所有的值类(Integer, Short....),以及所有的枚举类型都实现了Comparable接口。

接下来我们先看一下应该怎么实现这个接口,以及应该怎么使用它:

类对象(第一种实现方式)

public class DemoComparable implements Comparable<DemoComparable>{

    private int id;

    private String name;

    private int sort;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getSort() {
        return sort;
    }

    public void setSort(int sort) {
        this.sort = sort;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        DemoComparable that = (DemoComparable) o;
        return id == that.id &&
                sort == that.sort &&
                Objects.equals(name, that.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, sort);
    }

    @Override
    public String toString() {
        return "DemoComparable{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", sort=" + sort +
                '}';
    }

    @Override
    public int compareTo(DemoComparable o){
        if (o == null){
            throw new NullPointerException();
        }
        // 初始化result对象
        int result = 0;
        // 比较sort属性
        result = Integer.compare(sort, o.getSort());
        // 如果相同则继续比较下一属性,不相等则返回比较结果
        if (result != 0){
            return result;
        }
        // 比较id属性
        result = Integer.compare(id, o.getId());
        // 如果相同则继续比较下一属性,不相等则返回比较结果
        if (result != 0){
            return result;
        }

        return result;
    }
}

数组排序

public class MainTest {

    public static void main(String[] args) {
        /**
         * 生成对象的随机数组
         */
        DemoComparable[] array = new DemoComparable[100];
       for (int i = 0; i < 100; i++){
           DemoComparable var = new DemoComparable();
           // 获取随机数
           Random random = new Random();
           int rd = random.nextInt();
           var.setId(rd);
           var.setName("name"+rd);
           var.setSort(rd);
           array[i] = var;
       }
       // 排序
        Arrays.sort(array);
       // 输出结果
       for (int i = 0; i < array.length; i++){
           System.out.println(array[i].toString());
       }
    }
}

list排序

public class MainTest {

    public static void main(String[] args) {
        /**
         * 生成对象的随机集合
         */
        List<DemoComparable> array = new ArrayList<>();
        for (int i = 0; i < 100; i++){
            DemoComparable var = new DemoComparable();
            // 获取随机数
            Random random = new Random();
            int rd = random.nextInt();
            var.setId(rd);
            var.setName("name"+rd);
            var.setSort(rd);
            array.add(var);
        }
        // 排序
        Collections.sort(array);
        // 输出结果
        for (int i = 0; i < array.size(); i++){
            System.out.println(array.get(i).toString());
        }
    }
}

当我们实现Comparable接口时要注意:

  1. 在compareTo方法中使用关系操作符 < 和 > 是非常繁琐的,并且容易出错,因此不建议使用。
  2. 如果一个类有多个属性需要进行排序,那么按照什么样的顺序来进行排序是非常关键的,我们需要从最关键的属性开始。
  3. compareTo方法的结果应该尽量与equals方法的结果保持一致,即当a.compareTo(b)等于0时,a和b的equals方法返回的结果应该是true。当然,如果他们不一致的话也不会产生灾难性的后果,但是如果在一个有序集合中包含了该类的元素,这个集合就可能无法遵守相应集合接口(Collection,Set,Map)的通用约定。因为这些接口的通用约定是按照equals方法来定义的,但有序集合使用了由compareTo方法而不是equals方法所施加的等同性测试。

接下来我们介绍一下对象类的第二种实现方式,性能损耗上要比第一种更大一些:

public class DemoComparable1 implements Comparable<DemoComparable1>{

    /**
     * 构建静态比较器,性能损耗相较于上一种方式大约10%
     */
    private static final Comparator<DemoComparable1> COMPARATOR =
            Comparator.comparingInt((DemoComparable1 dc) -> dc.id)
            .thenComparingInt(dc -> dc.sort);

    /**
     * 比较方法实现
     */
    @Override
    public int compareTo(DemoComparable1 o) {
        return COMPARATOR.compare(this, o);
    }

    private int id;

    private String name;

    private int sort;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getSort() {
        return sort;
    }

    public void setSort(int sort) {
        this.sort = sort;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        DemoComparable1 that = (DemoComparable1) o;
        return id == that.id &&
                sort == that.sort &&
                Objects.equals(name, that.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, sort);
    }

    @Override
    public String toString() {
        return "DemoComparable1{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", sort=" + sort +
                '}';
    }
}

其排序方式与第一种实现方式是一样的。

后一种方式中,Comparable类具备全套的构造方法。对于基本类型long和double都有对应的comparingInt和thenComparingInt。int版本也可以用更狭义的整数型类型,如Short。Double版本也可以用float。这样便覆盖了所有Java数字型基本类型。

上一篇:数据结构与算法 06 排序_Compareble接口&&冒泡排序


下一篇:java 常见排序算法