• 【Java】Comparable和Comparator接口


    活动地址:CSDN21天学习挑战赛
    在这里插入图片描述博客主页: XIN-XIANG荣
    系列专栏:【Java SE】
    一句短话: 难在坚持,贵在坚持,成在坚持!

    一. Comparable接口

    1. Comparable简介

    Comparable是排序接口。

    若一个类实现了Comparable接口,就意味着该类支持排序。

    实现了Comparable接口的类的对象的列表或数组可以通过Collections.sort或Arrays.sort进行自动排序。

    Comparable接口的源码

    public interface Comparable<T> {
            public int compareTo(T o);
    }
    
    • 1
    • 2
    • 3

    2. 为什么要实现Comparable接口

    一个类型实现了Compareable接口,表明了这个类具有了可排序的功能或者说标准,两个对象通过Compareable接口中的compareTo方法的返回值来比较大小。

    首先定义一个学生对象, 再给定一个学生对象数组, 对这个对象数组中的元素进行排序(按年龄升序), 我们知道操作数组的工具包Arrays中有一个现成的 sort 方法可以给数组元素进行排序, 能否直接使用这个方法呢?

    class Student {
        private String name;
        private int age;
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
        
    public class Test {
        public static void main(String[] args) {
            Student[] stu = {
                    new Student("zhansan",18),
                    new Student("lisi", 20),
                    new Student("zhaoliu",15)
            };
            
            Arrays.sort(stu);
            System.out.println(Arrays.toString(stu));
        }
    }
    
    • 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

    程序运行时出现了类型转换异常

    img

    此时去跳转到异常提示的位置查看,可以发现源码中是将数组元素强制转换为Comparable类型,再去调用其中的compareTo方法,而此时我们自定义类型Student与Comparable毫不相干,Student类中是没有compareTo方法的。

    img

    再看一个例子,定义一个字符串数组将其排序后输出

    import java.util.Arrays;
    
    public class Test {
        public static void main(String[] args) {
            String[] str = {"xin","abc","rong","def"};
            Arrays.sort(str);
            System.out.println(Arrays.toString(str));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    执行发现可以完成排序

    img

    再去观察String类的源码,可以发现String类也实现了Comparable接口重写了compareTo方法

    img

    img

    此时就可以理解实现Comparable接口的原因

    3. Comparable的实际应用

    理解了Comparable接口后再来实现 给对象数组排序

    让 Student 类实现 Comparable 接口, 并实现其中的 compareTo 方法

    在 sort 方法中会自动调用 compareTo 方法, compareTo 的参数是 Object , 其实传入的就是 Student 类型的对象.

    然后比较当前对象和参数对象的大小关系(按年龄来算). 如果当前对象应排在参数对象之前, 返回大于 0 的数字; 如果当前对象应排在参数对象之后, 返回小于于 0 的数字; 如果当前对象和参数对象不分先后, 返回 0; 再次执行程序, 结果就符合预期了.

    import java.util.Arrays;
    
    class Student implements Comparable<Student>{
        private String name;
        private int age;
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    
        @Override
        public int compareTo(Student o) {
            if (this.age == o.age){
                return 0;
            }else if (this.age < o.age){
                return -1;
            }else {
                return 1;
            }
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            Student[] stu = {
                    new Student("zhansan",18),
                    new Student("lisi", 20),
                    new Student("zhaoliu",15)
            };
    
            Arrays.sort(stu);
            System.out.println(Arrays.toString(stu));
        }
    }
    
    • 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

    执行结果:

    img

    注意事项:

    对于 sort 方法来说, 需要传入的数组的每个对象都是 “可比较” 的, 需要具备 compareTo 这样的能力. 通 过重写 compareTo 方法的方式, 就可以定义比较规则.

    这里自己实现一个 sort 方法来完成排序过程(使用冒泡排序)

    public static void bubbleSort(Comparable[] array) {
            for (int i = 0; i < array.length-1; i++) {
                for (int j = 0; j < array.length-1-i; j++) {
                    if(array[j].compareTo(array[j+1]) > 0) {
                        Comparable tmp = array[j];
                        array[j] = array[j+1];
                        array[j+1] = tmp; 
                    }
                }
            }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    Comparator接口

    1. Comparator简介

    Comparator是比较接口,我们如果需要控制某个类的次序,而该类本身不支持排序(即没有实现Comparable接口),那么我们就可以建立一个“该类的比较器”来进行排序,这个“比较器”只需要实现Comparator接口即可。也就是说,我们可以通过实现Comparator来新建一个比较器,然后通过这个比较器对类进行排序。

    Comparator接口源码:

    public interface Comparator<T> {
        int compare(T o1, T o2);
        boolean equals(Object obj);
    }
    
    • 1
    • 2
    • 3
    • 4

    可以看到Comparator接口中包含两个抽象抽象方法,分别是为compare, equals,但类实现此接口时,只需要实现的接口只有compare方法即可;

    Java中类都继承于Object类,而Object类默认实现了equals方法,所以类实现Comparator接口,实现类中不需要必须去实现equals方法,可以理解为虽然我们没有去实现,但实现类继承于Object类,相当于实现类中已经默认实现了equals方法

    2. Comparator接口的实际运用

    Arrays.sort()中有下面给出的重载,可以用来排序自定义类型

    • Arrays.sort(T[] a, Comparator c);

    此时的sort方法中的第二个参数我们传入一个实现了java.util.Comparator接口的实例,所以在排序自定义类型时可以定义一个比较器去实现

    下面分别以以对象的name和age属性定义俩个比较器,分别以这两个比较器去实现排序

    在以name进行比较时,实际上是以字符串进行比较,String类实现了Comparable接口,所以可以直接调用comparTo方法。

    import java.util.Arrays;
    import java.util.Comparator;
    
    class AgeComparator implements Comparator<Student> {
    
        @Override
        public int compare(Student o1, Student o2) {
            return o1.getAge() - o2.getAge();
        }
    }
    
    class NameComparator implements Comparator<Student> {
    
        @Override
        public int compare(Student o1, Student o2) {
            return o1.getName().compareTo(o2.getName());
        }
    }
    
    class Student {
        private String name;
        private int age;
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    
        public String getName() {
            return name;
        }
    
        public int getAge() {
            return age;
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            Student[] stu = {
                    new Student("ghi",18),
                    new Student("def", 15),
                    new Student("abc",20)
            };
            System.out.println("以年龄进行排序");
            Arrays.sort(stu, new AgeComparator());
            System.out.println(Arrays.toString(stu));
    
            System.out.println("再以姓名进行排序");
            Arrays.sort(stu, new NameComparator());
            System.out.println(Arrays.toString(stu));
        }
    }
    
    • 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

    执行结果:

    img下面的代码是使用比较器比较对象

    public class Test {
        public static void main(String[] args) {
            Student student1 = new Student("xin",10);
            Student student2 = new Student("rong",40);
    
            AgeComparator ageComparator = new AgeComparator();
    
            if(ageComparator.compare(student1,student2) > 0) {
                System.out.println("student1 > student2");
            }else if(ageComparator.compare(student1,student2) == 0){
                System.out.println("student1 = student2");
            }else{
                System.out.println("student1 < student2");
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    执行结果:

    img

    三. Comparable和Comparator的比较

    Comparable是排序接口,若一个类实现了Comparable接口,就意味着“该类支持排序”;而Comparator是比较器,我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。

    Comparable相当于“内部比较器”,而Comparator相当于“外部比较器”。

    Comparable 对类的侵入性非常强, 一但投入使用便不方便再做修改,用起来比较简单,只要实现Comparable 接口的对象直接就成为一个可以比较的对象,需要重写comparTo方法,所以如果想要更换比较方式,就需要对comparTo “大动干戈”。

    Comparator 对类的侵入性比较弱, 使用起来非常灵活,用Comparator实现一个比较器, 当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了, 使用Comparator比较,如果想要更换比较方式,只需要在原来的基础上再增加一个比较器即可。

  • 相关阅读:
    无法安装Hyper-V 该固件中的虚拟化支持被禁用
    Gradle基础知识-Wrapper,Daeman;Groovy闭包语法
    解决mvn常用指令build failure的问题
    【数据结构】快排的详细讲解
    Ubuntu上Qt安装和配置的完整步骤
    Nginx内存池(内存池重置函数)
    C语言C位出道心法(三):共用体|枚举
    git学习——第4节 时光机穿梭
    22-07-29 西安 分布式事务、Seata
    Java+JSP+MySQL基于SSM的会议交接平台的设计与实现-计算机毕业设计
  • 原文地址:https://blog.csdn.net/Trong_/article/details/126432053