java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > java comparable接口和comparator接口

Java中的Comparable接口和Comparator接口核心机制详解

作者:ty正在添砖Java

Java中的Comparable和Comparator接口是实现对象比较和排序的两种核心机制,本文给大家介绍Java中的Comparable接口和Comparator接口区别,感兴趣的朋友一起看看吧

 Java 中的ComparableComparator接口是实现对象比较和排序的两种核心机制。

一个生动的比喻

想象一下排序一班的学生:

一、Comparable接口(内部比较器)

当一个类实现了 Comparable接口,就表明它的实例具有一种天生的、默认的比较顺序。例如,StringIntegerDate等类都实现了 Comparable,所以我们可以直接对它们的列表进行排序。 

核心:重写接口中唯一的 compareTo(T o)方法。

规则:this(当前对象)与参数对象 o比较。

返回一个负整数、零或正整数,分别表示 this小于、等于或大于 o。

下面我们举一个例子分别实现对Student的年龄和姓名进行比较:

年龄比较:

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;
    }
    public int getAge() {
        return age;
    }
    public String getName(){
        return name;
    }
    //年龄排序
    public int compareTo(Student o){
//        return this.age - o.age;
        return Integer.compare(this.age,o.age);
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class Test01 {
    public static void main(String[] args) {
        //按照年龄从小到大排序
        Student[] students = new Student[]{
                new Student("xiaoming", 19),
                new Student("xiaohong",20),
                new Student("xiaohua",15),
                new Student("xiaoshuai",24),
        };
        System.out.println("排序前"+ Arrays.toString(students));
        //Arrays.sort()能够根据我们定义的 compareTo方法排序
        Arrays.sort(students);  
        System.out.println("排序后" + Arrays.toString(students));
            //两个对象进行比较
//        Student student1 = new Student("小明",28);
//        Student student2 = new Student("小红",19);
//        System.out.println(student1.compareTo(student2));    //输出9
//        <0 则s1<s2 =0则s1=s2 >0则s1>s2
}

修改一下Student类中的compareTo方法可以实现对姓名进行排序

//姓名排序
   public int compareTo(Student o){
       return this.name.compareTo(o.name);//在String中已经实现了compareTo方法,这里可直接调用
   }

根据ASCII值进行排序

为什么当我们的类实现了comparable接口后,我们能够直接通过Arrays.sort()方法对students数组按年龄或者姓名进行排序?

这是因为Arrays.sort()依赖于我们通过Comparable接口提供的比较规则。排序算法本身不知道如何比较两个Student对象,但是它知道可以调用我们实现的compareTo方法来获得比较结果,从而完成排序。

二、Comparator接口(外部比较器)

Comparator允许在不修改原类的情况下定义多种排序规则,是一种独立的比较器,更加灵活(定制排序)。

如何使用?

1.创建一个类实现Comparator<T>接口

2.重写接口中的 compare(T o1, T o2)方法。

下面我们举一个例子分别实现对Student的年龄和姓名进行比较:

按年龄以及姓名长度比较:

import java.util.Arrays;
import java.util.Comparator;
class Teacher{
    private String name;
    private int age;
    public Teacher(String name,int age){
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    @Override
    public String toString() {
        return "Teacher{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class Test02 {
    public static void main(String[] args) {
        Teacher[] teachers = new Teacher[]{
                new Teacher("Zhang",33),
                new Teacher("Li",40),
                new Teacher("Hen",28),
                new Teacher("Tang",18)
        };
        //按照年龄大小比较
        AgeComparator ageComparator = new AgeComparator();
        System.out.println("排序前" + Arrays.toString(teachers));
        Arrays.sort(teachers,ageComparator);    //将实例化的比较器作为参数传入sort
        System.out.println("按年龄排序后" + Arrays.toString(teachers));
        //按照姓名长度比较
        NameLenComparator nameLenComparator = new NameLenComparator();
        Arrays.sort(teachers,nameLenComparator);    //将实例化的比较器作为参数传入sort
        System.out.println("按姓名长度排序后" + Arrays.toString(teachers));
    }
    //(静态内部类)自定义年龄比较器
    static class AgeComparator implements Comparator<Teacher>{
        public int compare(Teacher o1,Teacher o2){
            return o1.getAge()- o2.getAge();
        }
    }
    //(静态内部类)自定义姓名长度比较器
    static class NameLenComparator implements Comparator<Teacher>{
        public int compare(Teacher o1,Teacher o2){
            return o1.getName().length() - o2.getName().length();
        }
    }
}

我们发现,当我们实现了Comparator接口,使用Arrays.sort()时,将我们自定义的比较器实例化的对象作为参数传入sort中实现了自定义排序,这使我们能够自定义多种比较器且不改变原有类进行排序,非常灵活。

Java8+引入的Lambda表达式

Java8+中我们可以通过Lambda表达式来简化我们的比较器代码:

// 使用Lambda表达式替代完整的比较器类
        // 按年龄排序
        Arrays.sort(teachers, (t1, t2) -> t1.getAge() - t2.getAge());
        System.out.println("按年龄排序后: " + Arrays.toString(teachers));
        // 按姓名长度排序
        Arrays.sort(teachers, (t1, t2) -> t1.getName().length() - t2.getName().length());
        System.out.println("按姓名长度排序后: " + Arrays.toString(teachers));
        // 甚至可以更复杂:先按年龄,年龄相同按姓名长度
        Arrays.sort(teachers, (t1, t2) -> {
            int ageCompare = t1.getAge() - t2.getAge();
            if (ageCompare != 0) {
                return ageCompare;
            }
            return t1.getName().length() - t2.getName().length();
        });
        System.out.println("按年龄和姓名长度排序后: " + Arrays.toString(teachers));
    }

下面我们来详解一下这串代码中Lambda表达式的用法:

// 按年龄排序
Arrays.sort(teachers, (t1, t2) -> t1.getAge() - t2.getAge());

分解说明:

带代码块的Lambda表达式

// 先按年龄,年龄相同按姓名长度
Arrays.sort(teachers, (t1, t2) -> {
    int ageCompare = t1.getAge() - t2.getAge();
    if (ageCompare != 0) {
        return ageCompare;
    }
    return t1.getName().length() - t2.getName().length();
});

分解说明:

三、如何选择两个接口

Comparable接口和Comparator接口关键区别对比:

使用Comparable的情况

✅ 对象有明确的、唯一的自然排序规则

✅ 排序规则是对象固有的、不会改变的特性

✅ 你能够修改类的源代码

✅ 该排序规则会被频繁使用

示例:String, Integer, Date, BigDecimal

使用Comparator的情况

✅ 需要多种不同的排序规则

✅ 不能或不想修改原类代码

✅ 排序规则是临时的或特定于某个业务场景

✅ 需要复杂的、组合的排序逻辑

示例:报表排序、UI表格列排序、特殊业务规则排序

到此这篇关于Java中的Comparable接口和Comparator接口的文章就介绍到这了,更多相关java comparable接口和comparator接口内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

您可能感兴趣的文章:
阅读全文