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

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

文章目录

  • 深入理解Java比较器(Comparable和Comparator)
    • 一、 Comparable
      • 1、Comparable 接口定义
    • 二、Comparator 比较器接口
      • 2.1、Comparator接口原码
      • 2.2具体代码示例
    • 三、Comparator 和 Comparable 比较

在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);
}

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

大于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);
    }
}

此时:我们重写了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());
        }
    }

输出结果:

深入理解Java比较器(Comparable和Comparator)_第1张图片

总结:

此时因为我们已经重写了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);
}

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);
    }
}

编写测试类:

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());
        }
    }
}

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

        Arrays.sort(staff,((o1, o2) -> {
            if(o1.getHeight()==o2.getHeight()){
                return 0;
            }
            return o1.getHeight()-o2.getHeight();
        })) ;

原因;

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

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

深入理解Java比较器(Comparable和Comparator)_第2张图片

输出结果:

深入理解Java比较器(Comparable和Comparator)_第3张图片

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

三、Comparator 和 Comparable 比较

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

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

的自己。

你可能感兴趣的:(java,开发语言)