• Comparable和Comparator的区别



    一、Comparable与Comparator的相同点

    Comparable和Comparator都是java的一个接口,多用于实现集合中元素的比较及排序。
    当我们自定义一个类时,如果需要规定其中的排序规则时,我们就必须用到比较接口。例如:

    public class Person{
        private String name;//姓名
        private int age;//年龄
        private double height;//身高
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    我们定义了一个类,想规定其按照年龄进行比较,并且将Person类的对象存在List集合中,调用集合工具类中的 Collections.sort 排序方法,这时不能得到我们想要得到的结果。而我们 String 却不然,如果我们讲 String 存入到List集合中,它会按照一定的顺序进行排序,因为我们String类中实现了 Comparable 接口,并重写了接口中的 compareTo 方法,如下:

    public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;
        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    所以我们需要给自己定义的类定义一个比较的规则,我们就需要实现一个比较接口。

    二、Comparable 和 Comparator 的区别

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4ME8kKGu-1661411237720)(/img/bVcPjFj)]

    Comparable

    Comparable 定义在想要实现排序对象的类的内部,并且重写compareTo方法,例如:

    public class Person implements Comparable{
        private String name;//姓名
        private int age;//年龄
        private double height;//身高
        /**
         * 方法的作用就是定义比较规则
         * 返回值类型为int类型,取值范围分别为正数,负数,0
         * 正数:大于
         * 负数:小于
         * 0:等于
         * @param p
         * @return int
         */ 
         @Override
         public int compareTo(Person p) {
             return this.age - p.age;
         }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    当一个类实现了Comparable接口并重写了CompareTo方法时,我们使用Collections.sort进行排序的话,会自动调用其自定义的比较规则进行比较排序,CompareTo方法的返回值为int类型,有三种情况,分别为:

    1、自定义的比较规则中,比较着大于被比较者时,则返回正数;
    2、自定义的比较规则中,比较着小于被比较者时,则返回负数;
    3、自定义的比较规则中,比较着等于被比较者时,则返回0;

    Comparator

    Comparator 定义在想要实现排序对象的类的外部,并且重写compare方法。
    当一个类未定义比较规则,并且我们想要对其进行排序时,会使用你匿名内部类的方式或者重新自定义一个类并实现Comparator接口的方式来达到这个目的,例如:
    匿名内部类方式:

    public class PersonTest {
        public static void main(String[] args) {
            Person p1 = new Person("张三", 18, 180);
            Person p2 = new Person("李四", 20, 165);
            Person p3 = new Person("王五", 15, 175);
            List list = new ArrayList();
            list.add(p1);
            list.add(p2);
            list.add(p3);
            Collections.sort(list, new Comparator() {
                @Override
                public int compare(Person o1, Person o2) {
                    return o1.getAge()-o2.getAge();
                }
            });
            System.out.println(list);
     }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    自定义类实现Comparator接口

    public class PersonComparator implements Comparator {
        @Override
        public int compare(Person o1, Person o2) {
            return o1.getAge()-o2.getAge();
        }
    }
    public class PersonTest {
        public static void main(String[] args) {
            Person p1 = new Person("张三", 18, 180);
            Person p2 = new Person("李四", 20, 165);
            Person p3 = new Person("王五", 15, 175);
            List list = new ArrayList();
            list.add(p1);
            list.add(p2);
            list.add(p3);
            Collections.sort(list, new PersonComparator());
            System.out.println(list);
     }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    其实,从原理上来讲它们没有什么太大的不同,都是实现了 Comparator 接口并重写了 Compare 方法,只是写法上有些区别。当然从复用性的角度来讲,还是自定义的复用性更高一些,这里还需要实际看需求决定。它的比较规则和上述的Comparable中的CompareTo方法一样, Compare 方法的返回值也为int类型,也有三种情况,分别为:

    1、返回值类型为正数时,代表o1 > o2
    2、返回值类型为负数时,代表o1 < o2
    3、返回值类型为0时,代表o1 = o2

    三、注意事项

    无论是实现Comparable接口还是Comparator接口都需要指定泛型。

    四、总结

    实际上述两种方式各有利弊,实现Comparable使用比较简单,只要是实现了Comparable接口的类的对象,我们可以直接进行比较,但是在一些开发中我们开始未考虑到这里的情况下,想要改变就需要改变其源代码,不够方便;但是Comparator则不然,它可以在不修改源码的基础上,重新自定义一个比较器,这样降低了我们代码之间的耦合性,当我们之后想要改变一个比较算法时,也可以很方便的进行改变。我们只要重新定义一个比较规则即可。

    五、课后作业

    习题:
    一个班内有5名学生,用java写一段代码,将学生们按照年龄从大到小排序,如果年龄一样则按身高排序(高到低),如果身高也一样,按体重排序(轻到重)。
    答案:
    Stu学生类

    public class Stu implements Comparable{
        private Integer id;
        private String name;
        private Integer age;
        private Integer height;//165cm
        private Integer weight;//51kg
        public Stu() {
        }
        public Stu(Integer id, String name, Integer age, Integer height, Integer weight) {
            this.id = id;
            this.name = name;
            this.age = age;
            this.height = height;
            this.weight = weight;
        }
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Integer getAge() {
            return age;
        }
        public void setAge(Integer age) {
            this.age = age;
        }
        public Integer getHeight() {
            return height;
        }
        public void setHeight(Integer height) {
            this.height = height;
        }
        public Integer getWeight() {
            return weight;
        }
        public void setWeight(Integer weight) {
            this.weight = weight;
        }
        @Override
        public String toString() {
            return "Student{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", age=" + age +
                    ", height=" + height +
                    ", weight=" + weight +
                    '}';
        }
    
        @Override
        public int compareTo(Stu o) {
            /*
                1.按年龄从大到小排序
                2.如果年龄一样则按照身高排序(高到低)
                3.如果身高一样则按照体重排序(轻到重)
             */
            if (age.compareTo(o.getAge())!=0)
                return o.getAge().compareTo(age);
            if (height.compareTo(o.getHeight())!=0)
                return o.getHeight().compareTo(height);
            return weight.compareTo(o.getWeight());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    StuTests学生测试类

    public class StuTests {
        public static void main(String[] args) {
            List list = new ArrayList<>();
            Stu stu1 = new Stu(1002,"tom",21,170,55);
            Stu stu2 = new Stu(1001,"tony",21,170,56);
            Stu stu3 = new Stu(1005,"amy",20,180,51);
            Stu stu4 = new Stu(1004,"jack",23,184,59);
            Stu stu5 = new Stu(1003,"rose",23,150,66);
            list.add(stu1);
            list.add(stu2);
            list.add(stu3);
            list.add(stu4);
            list.add(stu5);
            list.forEach(stu -> System.out.println(stu));
            /*
              Stu{id=1002, name='tom', age=21, height=170, weight=55}
              Stu{id=1001, name='tony', age=21, height=170, weight=56}
              Stu{id=1005, name='amy', age=20, height=180, weight=51}
              Stu{id=1004, name='jack', age=23, height=184, weight=59}
              Stu{id=1003, name='rose', age=23, height=150, weight=66}
             */
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
  • 相关阅读:
    做好规划 拿下未来!
    Node.js之path路径模块
    冥想第九百五十八天
    第10篇:ESP32外部中断功能的使用
    docker 安装kafka
    共享内存+inotify机制实现多进程低延迟数据共享
    未来的人工智能会像流浪地球中的MOSS一样伪装,把人类带向属于它的未来吗?
    leetcode 27. 移除元素
    大数据技术学习笔记(五)—— MapReduce(2)
    【Python第三方包】使用Python的Translate包进行文本翻译
  • 原文地址:https://blog.csdn.net/weixin_46030002/article/details/126525409