• 深入理解Java比较器(Comparable和Comparator)


    深入理解Java比较器(Comparable和Comparator)


    在java中经常涉及到 对象数组的比较的情况,常见的有两种方法来处理:

    1. 继承comparable接口,并实现compareTo()方法
    2. 定义一个单独的对象比较器,继承自Comparator接口,实现compare()方法

    一、 Comparable

    若一个类实现了Comparable接口,就意味着该类支持排序。实现了 Comparable接口的类的对象的列表或数组可以通过Collections.sort或Arrays.sort进行自动排序。
    此外,实现此接口的对象可以用作有序映射中的键或有序集合中的集合,无需指定比较器
    此接口只有一个方法compare,比较此对象与指定对象的顺序,如果该对象小于、等于或大于指定 对象,则分别返回负整数、零或正整数。

    1、Comparable 接口定义

    Comparable 接口仅仅只包括一个函数,如下

    package java.lang;
    import java.util.*;
    
    public interface Comparable {
        //必须实现的抽象方法
        public int compareTo(T o);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    说明:根据这个方法的返回值来判断

    大于0:说明前一个比后一个大

    小于0:说明前一个小于后一个

    等于0:说明这两个一样大

    示例:

    这里有一个员工类Employee1,我们需要堆员工实体对员工的工资进行排序,所以这里用实现Comparable接口,重写compareTo方法

    import java.util.Arrays;
    
    public class Employee1 implements Comparable<Employee1>{
    
        private String name;
        private double salary;
    
        public Employee1(String name , double salary){
            this.name = name;
            this.salary = salary;
        }
    
        public Employee1(String name , double salary, int height){
            this.name = name;
            this.salary = salary;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Double getSalary() {
            return salary;
        }
    
        public void setSalary(Double salary) {
            this.salary = salary;
        }
    
        public void raiseSalary(double byPercent) {
            double raise = salary * byPercent / 100;
            salary += raise;
        }
    
        @Override
        public String toString() {
            return "Employee1{" +
                    "name='" + name + '\'' +
                    ", salary=" + salary +
                    '}';
        }
    
        /**
         * 重写排序规则:
         * 定义我们的排序规则,用salary来排序
         * @param other
         * @return
         */
        @Override
        public int compareTo(Employee1 other) {
            return Double.compare(salary,other.salary);
        }
    }
    
    • 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

    此时:我们重写了compareTo方法,可以看出是用成员变量salary进行了比较,当前一个对象小于后一个对象时,返回小于0,反之大于0,等于则返回0.

    测试类:

    	public static void main(String[] args) {
            Employee1[] temp=new Employee1[4];
            temp[0]=new Employee1("张三",150);
            temp[1]=new Employee1("李四",120);
            temp[2]=new Employee1("王五",135);
            temp[3]=new Employee1("小花",80);
            Arrays.sort(temp);
            for (Employee1 employee1 : temp) {
                System.out.println(employee1.toString());
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    输出结果:

    在这里插入图片描述

    总结:

    此时因为我们已经重写了compareTo方法,这里我们用实现Comparable的方法进行了对象的排序。

    二、Comparator 比较器接口

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

    2.1、Comparator接口原码

    特别说明

    若一个类要实现Comparator接口:它一定要实现compareTo(T o1, T o2) 函数,但可以不实现 equals(Object obj) 函数。
    为什么可以不实现 equals(Object obj) 函数呢? 因为任何类,默认都是已经实现了equals(Object obj)的。 Java中的一切类都是继承于java.lang.Object,在Object.java中实现了equals(Object obj)函数;所以,其它所有的类也相当于都实现了该函数。

    package java.util;
    
    public interface Comparator {
    
    	int compare(T o1, T o2);
        
    	boolean equals(Object obj);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    int compare()方法

    返回值为:

    小于0–>前一个对象小于后一个对象

    大于0–>前一个对象大于后一个对象

    等于0–>前一个对象等于后一个对象

    2.2具体代码示例

    背景

    此时,我们在Employee1类的基础上,我们再添加一个升高,但是这个类的依旧实现了Comparable接口,重写了compareTo方法,并且这个方法按照工资薪水排序,此时我们如何能都不改变代码的前提下,重新对升高排序呢?

    此时就引入了Comparator接口,我们实现这个接口的int compare方法,具体如下

    public class Employee implements Comparable<Employee>{
    
        private String name;
        private double salary;
        private int height;
    
        public Employee(String name , double salary){
            this.name = name;
            this.salary = salary;
        }
    
        public Employee(String name , double salary, int height){
            this.name = name;
            this.salary = salary;
            this.height= height;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Double getSalary() {
            return salary;
        }
    
        public int getHeight() {
            return height;
        }
    
        public void setHeight(int height) {
            this.height = height;
        }
    
        public void setSalary(Double salary) {
            this.salary = salary;
        }
    
        public void raiseSalary(double byPercent) {
            double raise = salary * byPercent / 100;
            salary += raise;
        }
    
        /**
         * 重写排序规则:
         * 定义我们的排序规则,用salary来排序
         * @param other
         * @return
         */
        @Override
        public int compareTo(Employee other) {
            return Double.compare(salary,other.salary);
        }
    }
    
    
    • 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

    编写测试类:

    public class EmployeeSortTest {
        public static void main (String[] args) {
            Employee[] staff = new Employee[4];
            staff[0] = new Employee ("张三" , 35000,175) ;
            staff[1] = new Employee ("李四" , 75000,165);
            staff[2] = new Employee ("王五" , 38000,180) ;
            staff[3] = new Employee ("小六" , 23000,153) ;
            //核心排序代码,对升高进行排序
            Arrays.sort(staff, Comparator.comparingInt(Employee::getHeight));
            //遍历数组结果
            for (Employee e : staff){
                System.out.println("name=" + e.getName() + " ,salary=" + e.getSalary()+" ,height="+e.getHeight());
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    对于核心排序代码,我们也可以用lambda表达式来编写:

            Arrays.sort(staff,((o1, o2) -> {
                if(o1.getHeight()==o2.getHeight()){
                    return 0;
                }
                return o1.getHeight()-o2.getHeight();
            })) ;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    原因;

    从Arrays.sort()源码的角度分析,sort方法接收的参数类型,一个为数组类型,一个为Comparator对象,因为Comparator为接口所以不能实例化,但是我们可以用多态来指向它,我们可以声明Comparator的实现类对象指向这个接口,此时就可以调用这个接口。

    当我们用lambda表达式时,也是创建了这个Comparator接口的具体实现方法,所以两者都可以进行排序,看读者的自己。

    在这里插入图片描述

    输出结果:

    在这里插入图片描述

    此时我们的这个数组对象就已经按照升高排序,实现需求。

    三、Comparator 和 Comparable 比较

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

    而Comparator是比较器;我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。

    的自己。

  • 相关阅读:
    Java8强大的新特性 —— “Stream API”
    0 upgraded, 0 newly installed, 0 to remove and 112 not upgraded解决方法
    uni-app 开发中,监听 input 键盘事件获取不到按下按键值怎么办?
    Java面试附答案:掌握关键技能,突破面试难题!
    Linux系统编程——文件的打开及创建
    Python学习笔记 - 面向对象编程
    英伟达再放AI芯片“大招” H200 GPU是人工智能技术的里程碑
    DataObjectImpl
    CH9101芯片应用—硬件设计指南
    Hadoop3教程(六):HDFS中的DataNode
  • 原文地址:https://blog.csdn.net/qq_45830276/article/details/126716358