zoukankan      html  css  js  c++  java
  • 13-Java中Comparable和Comparator的区别?

    下面分别对Comparable 和 Comparator做具体介绍并总结。

    Comparable

    Comparable可以认为是一个内比较器,实现了Comparable接口的类有一个特点,就是这些类是可以和自己比较的,至于具体和另一个实现了Comparable接口的类如何比较,则依赖compareTo方法的实现。

    如果add进入一个Collection的对象想要Collections的sort方法帮你自动进行排序的话,那么这个对象必须实现Comparable接口。compareTo方法的返回值是int,有三种情况:

    • 比较者大于被比较者,返回正整数

    • 比较者等于被比较者,返回0

    • 比较者小于被比较者,返回负整数

    写个很简单的例子:

    /**
     * 实现Comparable重写compareTo方法进行Person的排序, 这里根据年龄排序
     * 
     * @author 
     * @date 
     */
    @Getter
    @Setter
    @ToString
    @AllArgsConstructor
    @NoArgsConstructor
    public class Person implements Comparable<Person> {
    
        private String name;
        private int age;
    
        @Override
        public int compareTo(Person p) {
            // return p.getAge() - this.getAge()
            return this.getAge() - p.getAge();
        }
    }
    public class Demo {
    
        public static void main(String[] args) {
    
            Person p1 = new Person("aaa", 11);
            Person p2 = new Person("bbb", 5);
            Person p3 = new Person("cc", 8);
    
            Person[] ps = {p1, p2, p3};
            System.out.println(Arrays.toString(ps)); // 排序前
            Arrays.sort(ps);
            System.out.println(Arrays.toString(ps)); // 排序后
    
            System.out.println("----------------");
    
            Map<Person, String> map = new TreeMap<>();
            map.put(p1, "aaa");
            map.put(p2, "bbb");
            map.put(p3, "ccc");
            System.out.println(map.toString());
    
            System.out.println("----------------");
    
            List<Person> list = new ArrayList<>();
            list.add(p1);
            list.add(p2);
            list.add(p3);
            Collections.sort(list); // 排序
            System.out.println(list.toString());
        }
    }

    执行结果:

    [Person(name=aaa, age=11), Person(name=bbb, age=5), Person(name=cc, age=8)]
    [Person(name=bbb, age=5), Person(name=cc, age=8), Person(name=aaa, age=11)]
    ----------------
    {Person(name=bbb, age=5)=bbb, Person(name=cc, age=8)=ccc, Person(name=aaa, age=11)=aaa}
    ----------------
    [Person(name=bbb, age=5), Person(name=cc, age=8), Person(name=aaa, age=11)]

    Comparator

    Comparator接口里面有一个compare方法,方法有两个参数T o1和T o2,是泛型的表示方式,分别表示待比较的两个对象,方法返回值和Comparable接口一样是int,有三种情况:

    • o1大于o2,返回正整数

    • o1等于o2,返回0

    • o1小于o3,返回负整数

    写个很简单的例子:

    public class ComparatorDemo {
        
        public static void main(String[] args) {
            /**
             * 按照数组元素长度排序
             */
            String[] str = {"abcdeftg", "maidi", "kebi", "zhanmusi"};
            
            Arrays.sort(str, new Comparator<String>() {
                public int compare(String o1, String o2) {
                    return o1.length() - o2.length();
                }
            });
            System.out.println(Arrays.toString(str));
    }

    这里的Arrays.sort对数组进行排序用到了Compartor接口, 上面使用了匿名函数的写法, 也可以使用lambda进行改造...

    Arrays.sort(str, (o1, o2) -> o1.length() - o2.length());

    一行代码就可以搞定, 的确很简单

    运行结果

    [kebi, maidi, abcdeftg, zhanmusi]

    因为泛型指定死了,所以实现Comparator接口的实现类只能是两个相同的对象(不能一个自定义对象、一个String)进行比较,实现Comparator接口的实现类一般都会以"待比较的实体类+Comparator"来命名, 只不过这里使用了匿名函数更简单而已

    总结

    上面的例子不管是Comparable还是Comparator, 都是按照升序来排序的, 如果想要按照反过来的顺序, 改改代码即可, 只需要修改接口中的实现方法, 调换一下相减的两个比较对象或者值即可, 例如"// return p.getAge() - this.getAge()"注释掉的代码那里一样

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

    实现Comparable接口的方式比实现Comparator接口的耦合性要强一些,如果要修改比较算法,要修改Comparable接口的实现类,而实现Comparator的类是在外部进行比较的,不需要对实现类有任何修改。因此:

    • 对于一些普通的数据类型(比如 String, Integer, Double…),它们默认实现了Comparable 接口,实现了 compareTo 方法,我们可以直接使用。

    • 而对于一些自定义类,它们可能在不同情况下需要实现不同的比较策略,我们可以新创建 Comparator 接口,然后使用特定的 Comparator 实现进行比较。

    不同之处:

    实现Comparable接口的方式比实现Comparator接口的耦合性要强

  • 相关阅读:
    教师资格证考试全部重点名词解释
    计算机软考中高级职称评定条件
    如何计算教师工龄?工龄和教龄的区别
    vue.js中 this.$nextTick()的使用
    数组的合并 总结的几种方法
    CSS3实现了左右固定中间自适应的几种方法
    文本溢出省略号
    MVC/MVP/MVVM
    vue中父组件给子组件传值的方法
    vue实例的生命周期
  • 原文地址:https://www.cnblogs.com/no-celery/p/13666684.html
Copyright © 2011-2022 走看看