Java对象的比较——equals方法,Comparable接口,Comparator接口

news2025/2/23 6:26:38

Java对象的比较——equals方法,Comparable接口,Comparator接口

  • 1. equals方法
  • 2. Comparable接口
  • 3. Comparator接口

1. equals方法

在判断两个整数是否相同时,我们可以使用以下方式:

System.out.println(1 == 2);
System.out.println(1 == 1);

如果输出true,则说明这两个整数相同;如果输出false,则说明这两个整数不相同

那么,如果将==用于判断两个对象,又会是怎样的情况呢?我们直接敲代码来看看!

public class Dog {
    private String name;
    private int age;

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
public class Test1 {
    public static void main(String[] args) {
        Dog dog1 = new Dog("zhangsan",1);
        Dog dog2 = new Dog("zhangsan",1);
        System.out.println(dog1 == dog2);
    }
}

运行结果:
在这里插入图片描述
当运行这段代码时,我们发现输出的是false。明明dog1和dog2的属性都一模一样,为什么输出false呢?莫慌,且听我慢慢道来!
在这里插入图片描述
画图来分析,dog1和dog2中存放的值并不相同,因此dog1 != dog2。而你之所以认为输出的应该是true,是因为你认为,两个对象的属性完全一致,所以dog1 == dog2.其实,并不是这样的,==判断的并不是对象的属性是否一致,而是判断两个引用指向的是否是同一个对象!

在Java中,一切皆对象。而dog1和dog2是对象的引用。==判断的并不是对象的属性是否一致,而是判断两个引用指向的是否是同一个对象!

因此,只有当两个引用指向同一对象才返回true;而如果两个引用指向不同的对象,即使两个对象的属性完全相同,返回依旧是false!

总结:

  • 如果==左右两边是基本数据类型变量,比较的是变量中的值是否相同
  • 如果==左右两边是引用数据类型变量,比较的是引用变量中的值是否相同,而引用变量中存放的是对象的地址,所以比较的就是引用变量中存放的地址是否相同(即判断两个引用指向的是否是同一个对象!)

理解了这一点,学习equals方法就简单多了!我们先来看看equals方法的原型,equals方法在Object类中
在这里插入图片描述
有没有发现,equals方法,返回正是刚刚所讲的内容,说明equals方法默认就是判断两个引用指向的是否是同一个对象!

注意: equals方法的返回值是boolean类型!

再来尝试运行这段代码:

public class Test1 {
    public static void main(String[] args) {
        Dog dog1 = new Dog("zhangsan",1);
        Dog dog2 = new Dog("zhangsan",1);
        System.out.println(dog1.equals(dog2));
    }
}

运行结果依旧是false


那么,问题来了,如果我们想通过比较两个对象的属性是否相等,如果相等,从逻辑上就说明他们就是相等的,该怎么办呢?

我们知道Object类是一切类的父类,而equals方法在Object类中,是不是就通过可以重写equals方法,从而达到自定义比较方式的目的!

下面就演示重写equals方法,规则:如果两个对象的属性完全一致,则返回true;否则放回false

public class Dog {
    private String name;
    private int age;

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public boolean equals(Object obj) {
        Dog tmp = (Dog)obj;
        return this.name.equals(tmp.name) && this.age == tmp.age;
    }
}
public class Test1 {
    public static void main(String[] args) {
        Dog dog1 = new Dog("zhangsan",1);
        Dog dog2 = new Dog("zhangsan",1);
        System.out.println(dog1.equals(dog2));
    }
}

这时运行代码,输出的就是true!

这时,有人可能就有疑问了,为什么名字比较要用equals方法,其实这里的equals方法并非Dog类中的equals方法,而是String类中的equals方法,用来判断两个字符串是否相等

String类中的equals方法原型:
在这里插入图片描述
另外,编译器可以帮我们自动生成equals方法,第一步按住alt+insert
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
一路点下去,就可以生成equals方法,除此之外,还生成了hashCode方法
在这里插入图片描述

2. Comparable接口

通过重写equals方法,我们可以从逻辑上去判断两个对象是否相同。但是如果要去比较两个对象的大小,又该怎么去比较呢?对象的属性那么多,通过什么属性去比较呢?这时就需要讲到Comparable接口!

在这里插入图片描述
当我们在Student类后加上Comparable接口时,发现会报错,这是为什么呢?我们按住CTRL键,再鼠标左击Comparable,进入源码
在这里插入图片描述
我们发现,Comparable接口中还有个compareTo抽象方法,因此当我们在Student类要实现这个方法,除此之外,Comparable接口后还有个,这是泛型,我们需要比较什么类型的对象,就在实现接口时把T改成什么
在这里插入图片描述
由编译器自动生成实现compareTo方法的代码后:
在这里插入图片描述
我们就需要书写compareTo的方法体,那怎么书写呢?你想根据哪个对象的属性进行比较,就怎么书写。


比如,我现在想根据对象的年龄进行比较
在这里插入图片描述
下面进行测试:

public 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 int compareTo(Student o) {
        return this.age-o.age;
    }
}
public class Test {
    public static void main(String[] args) {
        Student student1 = new Student("zhangsan", 18);
        Student student2 = new Student("lisi", 10);
        System.out.println(student1.compareTo(student2));
    }
}

运行结果:
在这里插入图片描述
返回的是一个正数,说明根据年龄比较,student1大于student2


再比如,我不想根据年龄比较了,我想根据姓名比较,这时就不能用简单的this.name-o.name了,因为name是一个String类型,不能通过这样的方式进行比较
在这里插入图片描述
方法里的compareTo指并不是在Student类中具体实现的这个compareTo,而是String类中的conpareTo,用于字符串的比较,它的底层是和C语言的strcmp是一样的,返回的是两个字母的ASCII 码的差值
String类中的compareTo方法


那么,问题来了,前面我们比较的只有两个对象,如果需要比较多个对象呢,改怎么办呢?这时候就需要用到数组来存放对象,用Arrays里的排序方法进行排序

当我们写下以下代码:

public 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[] students = new Student[]{
                new Student("zhangsan",18),
                new Student("lisi", 10),
                new Student("wangwu", 20)};
        System.out.println("排序前:" + Arrays.toString(students));
        Arrays.sort(students);
        System.out.println("排序后:" + Arrays.toString(students));
    }
}

当我们运行代码后,发现会出现异常
在这里插入图片描述
在这里插入图片描述

这里需要用到强转,而Student类并没有去实现Comparable接口,因此会导致强转失败!这就是异常所在!所以,我们需要在Student类中实现Comparable接口

public 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) {
        return this.age-o.age;
    }
}

在这里插入图片描述

当我们再次去运行代码时,会发现排序后是根据年龄从小到大排序的,这和Student类中实现的compareTo难道有关系?答案是正确的

假如我们想按照年龄从大到小去排序,就做出如下更改
在这里插入图片描述
调换顺序即可,再次运行代码:
在这里插入图片描述


假如想根据年龄去比呢?

public 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) {
        return this.name.compareTo(o.name);
    }
}
public class Test1 {
    public static void main(String[] args) {
        Student[] students = new Student[]{
                new Student("zhangsan",10),
                new Student("lisi", 18),
                new Student("wangwu", 9)};
        System.out.println("排序前:" + Arrays.toString(students));
        Arrays.sort(students);
        System.out.println("排序后:" + Arrays.toString(students));
    }
}

3. Comparator接口

在前面使用Comparable接口来实现对象的比较时,我们不难发现,这个比较方法并不灵活,只能固定地通过一种方式去比较,那么如果我们有的时候想通过年龄比较,有的时候想通过姓名比较,这个接口就无法实现了,这时地解决办法就是,换一个接口,用Comparator接口来实现!

这时,我们分别写两个类——NameComparator和AgeComparator,代表分别通过姓名比较和通过年龄比较。并且这两个类都要实现Comparator接口!

import java.util.Comparator;

public class NameComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.getName().compareTo(o2.getName());//姓名通过compareTo方法进行比较
    }
}
import java.util.Comparator;

public class AgeComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.getAge() - o2.getAge();
    }
}

注意: 实现Comparator接口需要重写的时compare方法,不是compareTo方法!实现Comparable接口重写的才是compareTo方法!

学生类如下:

public class Student {
    private String name;
    private int age;

    public Student(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 "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

测试一下代码:

import java.util.Arrays;

public class Test {
    public static void main(String[] args) {
        //两个对象的比较
        AgeComparator ageComparator = new AgeComparator();
        NameComparator nameComparator = new NameComparator();
        Student student1 = new Student("zhangsan", 20);
        Student student2 = new Student("lisi", 30);
        System.out.println("根据年龄比:" + ageComparator.compare(student1, student2));
        System.out.println("根据姓名比:" + nameComparator.compare(student1, student2));

        //一组对象的比较
        Student[] students = new Student[]{
                new Student("zhangsan", 10),
                new Student("lisi", 18),
                new Student("wangwu", 9)};
        System.out.println("排序前:" + Arrays.toString(students));
        Arrays.sort(students, ageComparator);
        System.out.println("根据年龄排序后:" + Arrays.toString(students));
        Arrays.sort(students, nameComparator);
        System.out.println("根据姓名排序后:" + Arrays.toString(students));
    }
}

分析两个对象的比较:
在这里插入图片描述
这里,我们创建了一个AgeComparator和一个NameComparator对象,用来表示是通过年龄比较还是通过姓名比较。注意最后两个Student类对象的比较方法

分析一组对象的比较:
在这里插入图片描述
我们发现,在用Arrays.sort排序时,里面还加上了一个ageComparator对象(或NameComparator对象),通过这个对象,可以控制通过什么方式去比较,当使用Arrays对数组进行排序时,就会调用ageComparator(或NameComparator)里的compare方法依次将数组里的对象进行比较

最后,运行结果:
在这里插入图片描述


请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1721413.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多普云DPGo摄影测量航线规划软件

1.航线代规划。支持GSR航线&#xff08;大疆精灵4RTKSDK遥控器&#xff09;、DJI Pilot航线&#xff08;大疆精灵4RTK、M300&#xff09;、DJI Pilot2航线&#xff08;大疆精灵4RTK、M300、Mavic3E&#xff09;。 2.DPGO三维模型满足毫米级精度要求&#xff1a;已知被摄范围&am…

基于java的CRM客户关系管理系统(二)

目录 第二章 相关技术介绍 2.1 后台介绍 2.1.1 B/S平台模式 2.1.2 MVC 2.1.3 Spring 2.1.4 Hibernate 2.1.5 Struts 2.2 前端介绍 2.2.1 JSP网页技术 2.3 开发工具 2.4 本章小结 前面内容请移步 基于java的CRM客户关系管理系统&#xff08;二&#xff09; 资源…

vscode编辑器创建分支注意事项?!

最近在公司开发项目时&#xff0c;不小心将自己分支的东西提交到公司的master的分支&#xff0c;大家看看是什么情况&#xff1f; 先上图&#xff1a; 从图上看&#xff0c;我这边用了GITLENS这个插件&#xff0c;在创建分支时&#xff0c;有个create branch from&#xff0c;有…

如何选择软件开发服务商

在当今数字化快速发展的时代&#xff0c;软件已经成为企业运营不可或缺的一部分。然而&#xff0c;对于许多非技术背景的企业来说&#xff0c;如何选择一个合适的软件开发服务商却是一个不小的挑战。本文将从需求分析、服务商评估、合同条款以及后期维护等方面&#xff0c;详细…

【GD32F303红枫派使用手册】第五节 FMC-片内Flash擦写读实验

5.1 实验内容 通过本实验主要学习以下内容&#xff1a; FMC控制器原理&#xff1b; FMC擦写读操作&#xff1b; 5.2 实验原理 5.2.1 FMC控制器原理 FMC即Flash控制器&#xff0c;其提供了片上Flash操作所需要的所有功能&#xff0c;在GD32F303系列MCU中&#xff0c;Flash…

环卫车北斗GPS视频监控定位解决方案的应用与优势

一、引言 随着城市化进程的加快&#xff0c;环卫车作为城市环境卫生的重要保障力量&#xff0c;其运行效率与安全性直接关系到城市形象与居民生活品质。然而&#xff0c;传统的环卫车管理模式往往存在信息不对称、调度不合理、行驶不规范等问题&#xff0c;导致城市道路污染和…

Java中的软引用,你了解吗?

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

打工人福音,办公神器软件

今天分享2个免VIP的办公神器app&#xff0c;建议所有手机安装&#xff0c;第一个布丁扫描http://www.budingscan.com &#xff0c;无广告不收费&#xff0c;这是VIVO 推出的一款完全免费的扫描APP&#xff0c;支持文档&#xff06;证件扫描、OCR文字&#xff06;表格识别提取、…

解决Windows 10通过SSH连接Ubuntu 20.04时的“Permission Denied”错误

在使用SSH连接远程服务器时&#xff0c;我们经常可能遇到各种连接错误&#xff0c;其中“Permission denied, please try again”是较为常见的一种。本文将分享一次实际案例的解决过程&#xff0c;帮助你理解如何排查并解决这类问题。 问题描述 在尝试从Windows 10系统通过SS…

js:flex弹性布局

目录 代码&#xff1a; 1、 flex-direction 2、flex-wrap 3、justify-content 4、align-items 5、align-content 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewp…

Mysql基础教程(13):GROUP BY

MySQL GROUP BY 【 GROUP BY】 子句用于将结果集根据指定的字段或者表达式进行分组。 有时候&#xff0c;我们需要将结果集按照某个维度进行汇总。这在统计数据的时候经常用到&#xff0c;考虑以下的场景&#xff1a; 按班级求取平均成绩。按学生汇总某个人的总分。按年或者…

【spring】Spring Boot3.3.0发布啦

spring最新版本 springboot官网&#xff1a;Spring Boot :: Spring Boot Spring Boot 3.3 发行说明&#xff1a;https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.3-Release-Notes 开发环境的要求对比表 Spring BootJDKSpringMavenGradle3.3.017 ~ 226.1…

Nginx实战:LUA脚本_环境配置安装

目录 一、什么是LUA脚本 二、Nginx中的LUA脚本 1、主要特点 2、用途 三、如何在nginx中使用LUA脚本 1、原生nginx 2、OpenResty 3、nginx lua配置验证 一、什么是LUA脚本 Nginx Lua 脚本是 Nginx 与 Lua 语言集成的结果&#xff0c;它允许你使用 Lua 语言编写Nginx 模块…

【Redis】List源码剖析

大家好&#xff0c;我是白晨&#xff0c;一个不是很能熬夜&#xff0c;但是也想日更的人。如果喜欢这篇文章&#xff0c;点个赞&#x1f44d;&#xff0c;关注一下&#x1f440;白晨吧&#xff01;你的支持就是我最大的动力&#xff01;&#x1f4aa;&#x1f4aa;&#x1f4aa…

使用第三方工具percona-xtrabackup进行数据备份与恢复

目录 准备工作 开始安装 innobackupex的使用 完全备份 增量备份 数据恢复 本次需要用到的软件 mysql 5.7.35percona-xtrabackup-24-2.4.8 ps&#xff1a;---MySQL必须是5.7的版本&#xff0c;在8.0之后已经不支持 percona-xtrabackup-24 系统版本CentOS7.9 准备工作 …

面试题 17.05. 字母与数字(前缀和)

给定一个放有字母和数字的数组&#xff0c;找到最长的子数组&#xff0c;且包含的字母和数字的个数相同。 返回该子数组&#xff0c;若存在多个最长子数组&#xff0c;返回左端点下标值最小的子数组。若不存在这样的数组&#xff0c;返回一个空数组。 示例 1: 输入: ["…

SpringBoot+layui实现Excel导入操作

excel导入步骤 第三方插件引入插件 效果图 &#xff08;方法1&#xff09;代码实现&#xff08;方法1&#xff09;Html代码&#xff08; 公共&#xff09;下载导入模板 js实现 &#xff08;方法1&#xff09;上传文件实现 效果图&#xff08;方法2&#xff09;代码实现&#xf…

一碗米线火了24年,蒙自源六一再献新作

当一碗热气腾腾的米线在餐桌上飘香四溢&#xff0c;你是否会想起那个陪伴了无数食客24年的名字——蒙自源&#xff1f;在这个充满欢笑与童真的六一儿童节&#xff0c;蒙自源米线品牌再度发力&#xff0c;用全新的儿童餐系列为孩子们带来了一份特别的节日礼物。 蒙自源&#xf…

性价比为王,物流商怎么选择高效的国际物流管理平台

在全球化贸易日益繁荣的今天&#xff0c;国际物流行业作为链接国内商家和海外市场的重要桥梁&#xff0c;发挥着极其重要的作用。 然而&#xff0c;随着国际物流市场竞争的加剧&#xff0c;对物流商来说&#xff0c;也面临着成本管控和效率提升的双重挑战。今天我们会重点探讨…

AI之下 360让PC商业生态大象起舞

时隔7年&#xff0c;淘宝PC版在前不久迎来重磅升级&#xff0c;在产品体验、商品供给、内容供给等方面做了全面优化&#xff0c;以全面提升PC端的用户体验&#xff1b;当大家都以为移动互联网时代下APP将成为主流时&#xff0c;PC端却又成为了香饽饽。其实PC端被重视&#xff0…