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

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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic 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;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic 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> {@Overridepublic int compare(Student o1, Student o2) {return o1.getName().compareTo(o2.getName());//姓名通过compareTo方法进行比较}
}
import java.util.Comparator;public class AgeComparator implements Comparator<Student> {@Overridepublic 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;}@Overridepublic 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.mzph.cn/bicheng/20185.shtml

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

相关文章

安防综合管理系统EasyCVR平台GA/T1400视图库:基于XML的消息体格式

GA/T 1400标准的应用范围广泛&#xff0c;涵盖了公安系统的视频图像信息应用系统&#xff0c;如警务综合平台、治安防控系统、交通管理系统等。在视频监控系统中&#xff0c;GA/T 1400公安视图库的对接是实现视频图像信息传输、处理和管理的重要环节。 以视频汇聚EasyCVR视频监…

【SpringBoot】怎么在一个大的SpringBoot项目中创建多个小的SpringBoot项目,从而形成子父依赖

父子项目工程创建 步骤 先创建父项目 具体操作步骤请看本文章&#xff1a;使用maven工程创建spring boot项目 创建子项目 file- project structure module–new module 剩下步骤请看创建父工程时的操作使用maven工程创建spring boot项目 应用 确认即可 之后创建启动类…

ARM32开发——LED驱动开发

&#x1f3ac; 秋野酱&#xff1a;《个人主页》 &#x1f525; 个人专栏:《Java专栏》《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 需求介绍现实问题需求分析测试案例构建BSP驱动构建业务实现 需求介绍 开发版中有4个灯&#xff0c;现在需要用4个灯显示充电情况&a…

618大促有哪些好物是最值得入手的的?请收下这份618必买好物清单!

最近聊的最多的话题就是618&#xff0c;年中购物大狂欢马上来了&#xff01;&#xff01;今天整理了一下之前购买的好物&#xff0c;发现相比之前的价格真的是太划算了&#xff0c;赶紧分享出来给大家&#xff0c;趁着这个大促赶紧多存入手~ 推荐1、南卡Neo 2——不伤耳黑科技…

SPHINX的输出文档格式

SPHINX的输出文档格式 SPHINX的输出文档格式更多信息 SPHINX的输出文档格式 用rst编写&#xff0c;然后用sphinx-build进行编译&#xff0c;还是效果相当不错地&#xff0c;只要掌握了格式&#xff0c;可以一次编译&#xff0c;多种格式输出&#xff0c;主要是用的可能是html和…

记一次netty客户端的开发

背景 近日要开发一个tcp客户端程序去对接上游厂商的数据源&#xff0c;决定使用netty去处理&#xff0c;由于很久没有开发过netty了&#xff0c;顺便学习记录下 netty搭建 考虑到我们需要多个client去对接server服务&#xff0c;所以我们定义一个公共的AbstractNettyClient父…

LabVIEW与Arm控制器之间的通讯

LabVIEW是一个强大的图形化编程环境&#xff0c;广泛应用于自动化控制、数据采集和测试测量等领域。而Arm控制器则是嵌入式系统中常用的处理器架构&#xff0c;广泛用于各种控制和计算任务。将LabVIEW与Arm控制器进行通讯控制&#xff0c;可以结合二者的优势&#xff0c;实现高…

WordPress plugin MStore API SQL注入漏洞复现(CVE-2023-3077)

0x01 产品简介 WordPress和WordPress plugin都是WordPress基金会的产品。WordPress是一套使用PHP语言开发的博客平台。该平台支持在PHP和MySQL的服务器上架设个人博客网站。WordPress plugin是一个应用插件。 0x02 漏洞概述 WordPress plugin MStore API 3.9.8 版本之前存在S…

Linux 深入讲解自动化构建工具

各位大佬好 &#xff0c;这里是阿川的博客 &#xff0c; 祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 Linux一系列的文章&#xff08;质量分均在93分…

配置arduino和ESP8266

首先准备好arduino 的IDE和ESP8266的驱动以及板子 1.安装驱动&#xff0c;双击x64的版本驱动&#xff0c;安装好以后&#xff0c;在资源管理器检查端口&#xff0c;比如下下图出现的COM4就是esp8266所使用的端口 2.安装好arduino最好不要在路径中存在中文符号&#xff0c;打开…

水滴式粉碎机:多功能饲料粉碎设备

饲料粉碎机是一种专门用于将各种饲料原料进行粉碎处理的机械设备。无论是玉米、小麦等谷物&#xff0c;还是豆粕、鱼粉等动物性原料&#xff0c;甚至是一些粗纤维含量较高的秸秆、牧草等&#xff0c;都可以经过饲料粉碎机的处理&#xff0c;变成适合畜禽消化吸收的精细饲料。这…

521源码-游戏源码-2024卡牌回合自走棋手游《梦间集》推出全新Linux手工服务端

首款稀有卡牌回合自走棋手游《梦间集》推出全新Linux手工服务端整理 更多网站源码&#xff0c;游戏源码&#xff0c;学习教程&#xff0c;请点击&#x1f449;-521源码-&#x1f448;获取最新资源 本游戏下载地址&#xff1a;2024卡牌回合自走棋手游《梦间集》推出全新Linux手…

【再探】设计模式—中介者模式、观察者模式及模板方法模式

中介者模式让多对多的复杂引用关系变成一对多&#xff0c;同时能通过中间类来封装多个类中的行为&#xff0c;观察者模式在目标状态更新时能自动通知给订阅者&#xff0c;模版方法模式则是控制方法的执行顺序&#xff0c;子类在不改变算法的结构基础上可以扩展功能实现。 1 中…

ChatGPT AI专题资料合集【65GB】

介绍 ChatGPT & AI专题资料合集【65GB】 &#x1f381;【七七云享】资源仓库&#xff0c;海量资源&#xff0c;无偿分享√

文件系统小册(FusePosixK8s csi)【1 Fuse】

文件系统小册&#xff08;Fuse&Posix&K8s csi&#xff09;【1 Fuse&#xff1a;用户空间的文件系统】 Fuse(filesystem in userspace),是一个用户空间的文件系统。通过fuse内核模块的支持&#xff0c;开发者只需要根据fuse提供的接口实现具体的文件操作就可以实现一个文…

【测评|白嫖】雨云宁波新区,2C4G200M,公测期间全免费!

雨云香港三区云服务器&#xff0c;高性能的 Xeon Platinum 处理器 企业级 NVME SSD 高性能云服务器。 一键白嫖链接&#xff1a;https://www.rainyun.com 本篇纯测评&#xff0c;无任何广告&#xff0c;请放心食用&#xff01;&#xff01; 本次测评服务器配置如下&#xff1…

用万界星空科技低代码平台能快速搭建一个云MES系统

一、低代码平台与MES:智能制造的新篇章 随着工业4.0和智能制造的兴起&#xff0c;企业对于生产过程的数字化、智能化需求日益迫切。传统的MES系统实施周期长、成本高&#xff0c;成为许多企业数字化转型的瓶颈。而低代码开发平台的出现为这一问题提供了新的解决思路。 二、万界…

linux可观测性ebpf(一) ----------- 环境搭建

参考书籍 开发环境 Ubuntu 18.04.6 LTS (GNU/Linux 5.4.0-150-generic x86_64) 1.1 下载内核源码 cd /usr/src/ sudo git clone -b v5.4 https://github.com/torvalds/linux.git1.2 下载书中代码 git clone https://github.com/bpftools/linux-observability-with-bpf1.3 编…

海外媒体通稿:9个极具创意的旅游业媒体推广案例分享-华媒舍

如今&#xff0c;旅游业正迅速发展&#xff0c;媒体推广成为吸引游客的关键。为了更好地展示旅游目的地&#xff0c;许多创意而富有创新的媒体推广策略应运而生。本文将介绍九个极富创意的旅游业媒体推广案例&#xff0c;为广大从业者带来灵感和借鉴。 1. 视频系列&#xff1a;…

4. MySQL 约束

文章目录 【 1. 主键约束 PRIMARY KEY 】1.1 在创建表时设置主键约束设置单字段主键在创建表时设置联合主键 1.2 在修改表时添加主键约束1.3 删除主键约束1.4 主键自增长 AUTO_INCREMENT指定自增字段初始值自增字段不连续 【 2. 外键约束 FOREIGN KEY 】2.1 在创建表时设置外键…