Java中的比较器(Comparable和Comparator)

  在Java中,正常情况下,对象不能使用<、>进行比较,排序,而在开发中我们又需要对对象进行排序,比如TreeMap、TreeSet,再往里面添加数据时,需要让添加进去的对象排序好,这时就需要使用两个接口中的一个:Comparable和Comparator。

  很多情况下,我们需要对数据进行排序,但是java自带的比较器只能比较基本数据类型,比如我们自己定义一个Student类,如果用默认的Array.sort()方法进行排序,他会按照内存地址进行排序,那么这个排序毫无意义,此时我们就需要自己定义一个比较器,按照我们想要的比较方式来进行排序。

Comparable

  所有可以排序的类都实现了java.lang.Comparable接口,Comparable接口中只有一个方法:compareTo(Object obj),该方法返回0表示this==obj、返回正数表示this>obj、返回负数表示this<obj,实现了Comparable接口的类通过实现comparaTo方法从而确定该类对象的排序方式。

  一般被集合元素类所实现。

public class Student implements Comparable<Student>{
    /**
     * 编号
     */
    private int id;

    /**
     * 姓名
     */
    private String name;

    /**
     * 通过学生编号进行排序
     * @param o
     * @return
     */
    @Override
    public int compareTo(Student o) {
        return this.id - o.id;
    }
}

Comparator

  Comparator可以认为是一个外比较器,在一个对象不支持自己和自己比较(没有实现Comparable接口),但是又想对两个对象进行比较的情况下可以使用,Comparator接口里有一个compara(T o1, T o2)方法,方法有两个参数T o1和T o2,是泛型的表示方式,分别表示待比较的两个对象,方法返回值和Comparable接口一样是int,有三种情况:

  • o1大于o2,返回正整数
  • o1等于o2,返回零
  • o1小于o2,返回负整数

  Comparator接口一般有两种实现方式,单独实现,或者匿名内部类方式实现。

匿名内部类实现方式:

public class TreeSetDemo {
    public static void main(String[] args) {
        Set set = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                Clazz c1 = (Clazz) o1;
                Clazz c2 = (Clazz) o2;
                return c1.getId() - c2.getId();
            }
        });
        set.add(new Clazz(1,"name1"));
        set.add(new Clazz(2,"name2"));
        set.add(new Clazz(3,"name3"));
        // 遍历set
        for (Object obj : set) {
            System.out.println(obj);
        }
    }
}

单独实现:

public class TreeSetDemo {
    public static void main(String[] args) {
        Set set = new TreeSet(new ClazzComparatorOrder(false));
        set.add(new Clazz(1,"name1"));
        set.add(new Clazz(2,"name2"));
        set.add(new Clazz(3,"name3"));
        // 遍历set
        for (Object obj : set) {
            System.out.println(obj);
        }
    }

    /**
     * 排序器,静态内部类
     */
    private static class ClazzComparatorOrder implements Comparator {

        /**
         * 正向或逆向排序的标志
         */
        private boolean flag;
        /**
         * 排序器构造方法
         * @param flag 正向或逆向排序的标志
         */
        private ClazzComparatorOrder(boolean flag) {
            this.flag = flag;
        }
        @Override
        public int compare(Object o1, Object o2) {
            Clazz c1 = (Clazz) o1;
            Clazz c2 = (Clazz) o2;
            if (this.flag) {
                // 正向
                return c1.getId() - c2.getId();
            } else {
                // 逆向
                return c2.getId() - c1.getId();
            }
        }
    }
}

好处:可以通过构造方法输入true或者false来控制正向或逆向排序。

Comparable 与 Comparator的区别

  • 如果对象数组需要排序,那么就必须设置排序规则,就要使用这两种比较器。

  • 对于Comparable接口来说,它往往是进行比较类需要实现的接口,它仅包含一个有comparaTo()方法,只有一个参数。

  • 对于Comparator接口来说,它的实现者被称为比较器,它包含一个compara()方法,有两个参数,Comparator接口一般不会被集合元素类所实现,而是单独实现或者匿名内部类实现

  • Comparable接口的方式一旦实现,就可以保证Comparable的实现类在任何位置都可以比较大小。

  • Comparator接口属于临时性比较。

  • 如果实现类没有实现Comparable接口,又想对两个类进行比较(或者实现类实现了Comparable接口,但是对compareTo方法内的比较算法不满意),那么可以实现Comparator接口,自定义一个比较器,写比较算法。

  • 实现Comparable接口的方式比实现Comparator接口的耦合性要强一些,如果要修改比较算法,要修改Comparable接口的实现类,而实现Comparator的类是在外部进行比较的,不需要对实现类有任何修改。从这个角度说,其实有些不太好,尤其在我们将实现类的.class文件打成一个.jar文件提供给开发者使用的时候。

原文地址:https://www.cnblogs.com/zbh355376/p/14617154.html