【JAVA学习之路 | 提高篇】Java比较器(comparable) &&(comparator)

简介: 【JAVA学习之路 | 提高篇】Java比较器(comparable) &&(comparator)

1.前言

我们经常使用>,<,=等运算符来比较数与数之间的大小关系,但显然这些运算符并不同样适用于对象.但如果需要比较对象,那么我们应该怎么办呢?

我们可以考虑两种方法 : (1) 自然排序 (2). 定制排序.

2.自然排序(实现Comparable接口)

(1). 为什么String类的对象可以进行比较大小,正是因为String类实现了Comparable接口,并重写了comparaTo(Object o)方法.

(2). 操作步骤

  • 设计类实现Comparable接口
  • 重写compareTo(Object o)方法.在此方法中指明对象比较的标准.
  • 创建类的多个实例,调用Arrays.sort()方法比较.

(3). 例 :

public class Phone implements Comparable{
    private String name;
    private double price;
 
    public Phone() {
    }
 
    public Phone(String name, int price) {
        this.name = name;
        this.price = price;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public double getPrice() {
        return price;
    }
 
    public void setPrice(int price) {
        this.price = price;
    }
 
    @Override
    public int compareTo(Object o) {
        if (this == o) {
            return 0;
        }
        if (o instanceof Phone) {
            Phone p = (Phone) o;
            return Double.compare(this.price, p.price);
        }
        throw new RuntimeException();
    }
 
    @Override
    public String toString() {
        return "Phone{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}
 
 
public class PhhoneTest {
    public static void main(String[] args) {
        Phone[] p1 = new Phone[5];
        p1[0] = new Phone("xiaomi", 4900);
        p1[1] = new Phone("vivo", 5900);
        p1[2] = new Phone("oppo", 6900);
        p1[3] = new Phone("huawei", 7900);
        p1[4] = new Phone("iPhone", 8900);
        Arrays.sort(p1);
        for (int i = 0; i < p1.length; i++) {
            System.out.println(p1[i].toString());
        }
    }
}
 
控制台
Phone{name='xiaomi', price=4900.0}
Phone{name='vivo', price=5900.0}
Phone{name='oppo', price=6900.0}
Phone{name='huawei', price=7900.0}
Phone{name='iPhone', price=8900.0}

上面代码实现了price为标准实现了对象之间的比较.如果我们需要以name为标准我们应该怎么办呢?

只需要修改具体类(Phone)中重写的compareTo(Object o)方法.

@Override
    public int compareTo(Object o) {
        if (this == o) {
            return 0;
        }
        if (o instanceof Phone) {
            Phone p2 = (Phone) o;
            return p1.getName().compareTo(p2.getName());
        }
        throw new RuntimeException();
    }
 
控制台
Phone{name='huawei', price=7900.0}
Phone{name='iPhone', price=8900.0}
Phone{name='oppo', price=6900.0}
Phone{name='vivo', price=5900.0}
Phone{name='xiaomi', price=4900.0}

return语句中调用了String类重写的compareTo(Object o)方法.比较字符串对象大小.如果左边字符串比右边的小,返回负数.如果左边的比右边的大,返回正数.如果相等,返回0.上文Double.compare(double a,double b)方法同理.


3.定制排序(实现Comparator接口)

(1). 思考

  • 当元素所属的类没有实现java.lang.Comparable接口并且不方便修改时.
  • 如果一个类实现了Comparable接口,也指定了两个对象的比较规则,但我们不想按照它预定义的方式去比较对象,而且我们不能随意修改,那我们应该怎么办呢?
  • 如String[] s =new String[10];//静态初始化;Arrays.sort(s)是将字符串从小到大排序完毕,但我们期望将字符串从大到小排序,但我们不能随意修改String类中的源码,我们应该怎么办呢?

(2). 我们可以增加java.util.Comparator接口,强制按照我们想要的方式去比较对象.


  • 重写Conpare(Object o1, Object o2)方法,比较二者的大小.
  • 将Comparator接口的实现类的对象作为参数传入到sort方法中,从而允许以自己想要的方式进行排序.

(3). 例 : 以字符串为比较的依据进行对象的比较.此处使用匿名实现类的匿名对象更为方便.如果想以price作为比较的依据,只需改动Compare(Object o1, Object o2)方法即可.

public class PhhoneTest {
    public static void main(String[] args) {
        Phone[] p1 = new Phone[5];
        p1[0] = new Phone("xiaomi", 4900);
        p1[1] = new Phone("vivo", 5900);
        p1[2] = new Phone("oppo", 6900);
        p1[3] = new Phone("huawei", 7900);
        p1[4] = new Phone("iPhone", 8900);
        Arrays.sort(p1, new Comparator<Phone>() {
            @Override
            public int compare(Phone o1, Phone o2) {
                if (o1 == o2) {
                    return 0;
                }
                if (o1 instanceof Phone && o2 instanceof Phone) {
                    Phone a = (Phone) o1;
                    Phone b = (Phone) o1;
                    return a.getName().compareTo(b.getName());
                }
                throw new RuntimeException();
            }
        });
        for (int i = 0; i < p1.length; i++) {
            System.out.println(p1[i].toString());
        }
    }
}

4.两种方式的比较

(1).

自然排序比较单一,唯一.

定制排序比较灵活,多样.

(2).


自然排序是一劳永逸的.


定制排序是临时的.


(3).


自然排序对应的接口类型是Comparable,重写的是CompareTo(Object o)方法.


定制排序对应的接口类型是Comparator,重写的是Compare(Object o1, Object o2)方法


注意到为什么CompareTo方法的形参有一个,而Compare方法有两个.


很简单,因为this对象(该方法的调用者)跟传入方法的对象的类型相同,都是具体类(如上的Phone),而compareTo方法的this跟具体类的对象并无关系,充当传入sort方法的参数,所以将两个需要比较的对象都传入到Compare方法中.

相关文章
|
2月前
|
IDE Java 编译器
java编程最基础学习
Java入门需掌握:环境搭建、基础语法、面向对象、数组集合与异常处理。通过实践编写简单程序,逐步深入学习,打牢编程基础。
218 1
|
2月前
|
存储 Oracle Java
java零基础学习者入门课程
本课程为Java零基础入门教程,涵盖环境搭建、变量、运算符、条件循环、数组及面向对象基础,每讲配示例代码与实践建议,助你循序渐进掌握核心知识,轻松迈入Java编程世界。
297 0
|
3月前
|
Java API 容器
Java基础学习day08-2
本节讲解Java方法引用与常用API,包括静态、实例、特定类型方法及构造器引用的格式与使用场景,并结合代码示例深入解析。同时介绍String和ArrayList的核心方法及其实际应用。
159 1
|
2月前
|
负载均衡 Java API
grpc-java 架构学习指南
本指南系统解析 grpc-java 架构,涵盖分层设计、核心流程与源码结构,结合实战路径与调试技巧,助你从入门到精通,掌握高性能 RPC 开发精髓。
271 7
|
3月前
|
Java
Java基础学习day08-作业
本作业涵盖Java中Lambda表达式的应用,包括Runnable与Comparator接口的简化实现、自定义函数式接口NumberProcessor进行加减乘及最大值操作,以及通过IntProcessor处理整数数组,实现遍历、平方和奇偶判断等功能,强化函数式编程实践。
77 5
|
3月前
|
Java 程序员
Java基础学习day08
本节讲解Java中的代码块(静态与实例)及其作用,深入介绍内部类(成员、静态、局部及匿名)的定义与使用,并引入函数式编程思想,重点阐述Lambda表达式及其在简化匿名内部类中的应用。
151 5
|
3月前
|
Java
Java基础学习day07-作业
本作业包含六个Java编程案例:1)动物类继承与多态;2)加油卡支付系统;3)员工管理类设计;4)学生信息统计接口;5)USB设备控制;6)家电智能控制。综合运用抽象类、接口、继承、多态等面向对象技术,强化Java基础编程能力。
177 3
|
存储 安全 Java
24、使用 Java 官方教程学习:① 类变量和类方法详解;② 深入介绍 main() 方法
24、使用 Java 官方教程学习:① 类变量和类方法详解;② 深入介绍 main() 方法
191 1
【JAVA学习之路 | 进阶篇】Map接口及其实现类及常用方法
【JAVA学习之路 | 进阶篇】Map接口及其实现类及常用方法
|
Java 测试技术 C++
【JAVA学习之路 | 进阶篇】File类及常用方法
【JAVA学习之路 | 进阶篇】File类及常用方法