重写equals()方法

2023-11-04


1.如果想把持久类的实例放入set中(多值关联时,1对多),建议实现equals和hashcode

2.想重用托管实例时,也要实现equals和hashcode

3.多个字段组合作为联合主键,必须实现equals和hashcode方法

equals()和hashCode()这两个方法属于Object类,而Object类是所有类的父类,因此所有的类都继承了这两个方法。其中有一些类重写了这两个方法。

例如:Object类的equals()方法代码如下:
public boolean equals(Object obj) {  
    return (this == obj);  
    }  

这两个方法都来自于Object对象,根据API文档查看下原意。

(1)public boolean equals(Objectobj),对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true;

注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。

(2)public int hashCode() 返回该对象的哈希码值。支持该方法是为哈希表提供一些优点

    我们知道,如果不重写equals,那么比较的将是对象的引用是否指向同一块内存地址,重写之后目的是为了比较两个对象的value值是否相等。特别指出,此时,利用equals比较八大包装对象(如int,float等)和String类(因为该类已重写了equals和hashcode方法)对象时,默认比较的是值,在比较其它对象都是比较的引用地址。那产生了一个问题,为什么jdk中希望我们在重写equals时,非常有必要重写hashcode呢?

    我的理解是hashcode是用于散列数据的快速存取,如利用HashSet/HashMap/Hashtable类来存储数据时,都是根据存储对象的hashcode值来进行判断是否相同的。这样如果我们对一个对象重写了euqals,意思是只要对象的成员变量值都相等那么euqals就等于true,但不重写hashcode,那么我们再new一个新的对象,当原对象.equals(新对象)等于true时,两者的hashcode却是不一样的,由此将产生了理解的不一致,如在存储散列集合时(如Set类),将会存储了两个值一样的对象,导致混淆,因此,就也需要重写hashcode。

在集合类(HashMap,HashSet等)中判断两个对象是否相等有如下规则:

如果两个对象哈希值不同,那么这两个对象不相等。如果相同,则调用equals()方法判断,如果equals()方法返回true,则这两个对象相等,否则不相等。为了保证这种一致性,必须满足以下两个条件:
    (1)当obj1.equals(obj2)为true时,obj1.hashCode() == obj2.hashCode()必须为true

    (2)当obj1.hashCode() == obj2.hashCode()为false时,obj1.equals(obj2)必须为false

在实体类中重写equals方法和hashcode方法:

package org.test.entity;


public class User {
private int id;
private String uname;
private int age;
private String sex;
private String city;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
//重写Object类下的toString()方法
public String toString(){
return "User [id="+id+",uname="+uname+",age="+age+",sex="+sex+",city="+city+"]";
}


//第一步分析  
/*@Override 
public boolean equals(Object obj) { 
     *//** 
      * 这里要改进,根据这里的比较成员变量来决定返回true还是false 
      * 这里其实要比较的就是name,age和sex,city
      * 但是,name是String类型的,而String是引用类型的,所以,在这里不能直接用==比较, 
      * 应该用equals()比较 
      * this  -- s1 
      * obj -- s2 
      *//* 
     if(obj == null){ 
         return false; 
     } 
     //要使用的是用户类的特有成员,所以要向下转型 
     User s = (User)obj; // s -- obj -- s2 
     if(this.age == s.age && this.uname.equals(s.uname) && this.sex.equals(s.sex) && this.city.equals(s.city)){ 
              return true; 
         }else{ 
              return false; 
         } 
}*/  
  
//第二步优化  
/*   @Override 
public boolean equals(Object obj) { 
     //为了提高效率 
     if(this == obj){ 
         return true; 
     } 
      
     //为了提供程序的健壮性 
     //我先判断一下,obj是不是用户的一个对象,如果是,再做向下转型,如果不是,直接返回false 
     //这个时候,我们要判断的是对象是否是某个类的对象? 
     if (!(obj instanceof User)) { 
         return false; 
     } 
     //如果是就继续 
     User user = (User)obj; 
     System.out.println("同一个对象,还需要向下转型比较吗?"); 
     return this.uname.equals(s.uname) && this.age==s.age && this.sex.equals(s.sex)this.city.equals(s.city); 
}*/  
  


//重写equals要实现hachCode()  
@Override  
public int hashCode() {  
     final int prime = 31;  
     int result = 1;  
     result = prime * result + age;  
     result = prime * result + ((uname == null) ? 0 : uname.hashCode());  
     result = prime * result + ((sex == null) ? 0 : sex.hashCode());  
     result = prime * result + ((city == null) ? 0 : city.hashCode());  
     return result;  
}  
//第三步  
@Override  
public boolean equals(Object obj) {  
     if (this == obj)   //判断对象地址是否相等,如果是就不用判断,提高效率  
         return true;  
     if (obj == null)   //对象为空,则不往下走了  
         return false;  
     if (getClass() != obj.getClass())  //判断两个对象是否一样:class july.star.equals.Student--class july.star.equals.Student  
         return false;  
    User user = (User) obj;  //向下转型  
     /** 判断成员变量是否一样 */  
     if (age != user.age)     
         return false;  //判断年龄,int类型,直接比较
     //String类型,equals()比较
     if (uname == null) {  
         if (user.uname != null)  
              return false;  
     } else if (!uname.equals(user.uname))  
         return false;  
     if (sex == null) {  
         if (user.sex != null)  
              return false;  
     } else if (!sex.equals(user.sex))  
         return false;  
     if (city == null) {  
         if (user.city != null)  
              return false;  
     } else if (!city.equals(user.city))  
         return false; 
     return true;  
}


}

测试类:

package org.test.demo;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.test.entity.User;


public class UserTest {


  //定义变量


    Configuration config=null;


    SessionFactory sessionFactory=null;


    Session session=null;


    Transaction transaction=null;

@Test



public void equalsTest()
{
User user1=new User();
User user2=new User();


try {


  session=HibernateUtils.getSession();


  //4.开始事务


  transaction=session.beginTransaction();
//5.操作
user1=(User)session.get(User.class, 1);
 //6.提交事务


   transaction.commit();


   //7.关闭资源
   session.close();
   
} catch (HibernateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


try {


  session=HibernateUtils.getSession();


  //4.开始事务


  transaction=session.beginTransaction();
//5.操作
user2=(User)session.get(User.class, 1);

 //6.提交事务


   transaction.commit();


   //7.关闭资源
   session.close();


} catch (HibernateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(user1==user2);//重写前:false        重写后: false
System.out.println(user1.equals(user2));//false   true
User user3 = user1;   //地址引用,指向同一个地址  
System.out.println( user1 == user3);  //true      true
//false:this==obj 也是对地址的比较,所以要重写equals  
System.out.println(user1.equals(user3));  //true   true
System.out.println(user1.equals(user2));  //false   true
  
System.out.println("--------------");  
User user4 = new User();  
//重写后  
System.out.println(user1.equals(user2));  //true  
System.out.println(user1.equals(user3));    //true  
System.out.println(user1.equals(user4));    //false  
UserTest d = new UserTest ();  
System.out.println(user1.equals(d));  //false 判断是否为同一个对象  
}

}

在重写之前结果为:

重写后结果为:






本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

重写equals()方法 的相关文章

  • LeetCode题目笔记--2.两数相加

    这个博客系列记录我刷LeetCode过程中的一些循序渐进的思路和想法 希望能坚持下去 如果读者老爷觉得有帮助 就点个赞吧 题目描述 给出两个 非空 的链表用来表示两个非负的整数 其中 它们各自的位数是按照 逆序 的方式存储的 并且它们的每个
  • 数据导入hudi报错,错将字段写到hdfs路径上

    报错信息 Error trying to save partition metadata this is okay as long as atleast 1 of these succced file qiche hudi table 冬天
  • 2020无人用的邮箱和密码大全_Amazon后台登录密码错误!如何辨别账号是否被冻结?...

    啊你绝对不知道 这里每天都会更新一些跨境电商实时动态 卖家经验交流 跨境平台动态研究 曝光销售技巧 转化技巧 站外引流的方法 亚马逊后台登录密码错误 如何辨别账号是否被冻结 很多人一看到自己账号登录不进去就开始心慌 因为2018年就因为亚马
  • [QT编程系列-6]:C++图形用户界面编程,QT框架快速入门培训 - 3- QT窗体设计 - 自定义菜单栏

    目录 3 QT窗体设计 3 1 自定义菜单 3 1 1 设计目标 编辑 3 1 2 创建过程 编辑 3 QT窗体设计 3 1 自定义菜单 3 1 1 设计目标 3 1 2 创建过程 在Qt中 Windows窗口和Widget窗口是两种不同的
  • 如何用python加NLP打造自己的智能问答机器人

    一 基本流程 我们可以参照以下流程进行智能机器人的程序设计工作 1 利用已有的数据对 TfidfVectorizer 模型进行训练 2 利用训练好的TF IDF模型进行训练数据data0和真实数据data1的TFIDF值求解 3 通过余弦相
  • Spring Boot 3.x 构建系统&Starters

    系列文章目录 系列文章 Spring Boot 3 x 系列教程 文章目录 系列文章目录 前言 一 依赖管理 二 Maven 三 Spring Boot Maven Plugin 四 Starters 前言 Spring Boot 建议选择
  • c语言double类型的输入

    c语言double类型的输入 double输入用 lf 而不能用 f 今天在使用double类型输入时先用了 scanf lf a 结果以 f输出的时候都是0 以 g e输出似乎是最小的double值 12 3456789 0 000000
  • 软件产品设计

    figma软件介绍 Figma是一款在线协作式设计工具 用于 UI UX 设计和原型开发 它提供了一整套设计工具 包括向量绘图 页面布局和共享协作 支持多人协作 让用户可以在任何设备上创建 共享和讨论设计 知识点和技能 设计理论 理解UI设
  • Linux下xargs工具的使用

    xargs命令是给其他命令传递参数的一个过滤器 也是组合多个命令的一个工具 它能够将标准输入或管道中的数据转换为特定命令的命令行参数 也可以将单行或多行文本输入转换为其他格式的数据 比如单行变多行或者多行变单行 xargs的默认命令是ech
  • VS中的快捷键快速格式化代码,使好看,整齐

    在VC2005中 快捷键是Ctrl K Ctrl F 这是一个组合键 即先按Ctrl K 这时候编辑器会等待下一个按键动作 此时再按Ctrl F 即可以格式化代码了 当然 也可以在选项里面设置成使用VC6的快捷键 就可以继续使用Alt F8
  • 简述:面向对象的程序设计思想是什么?

    本博文源于C 基础 学到了类与对象这一章节 看见了课后有一个问题叫做 面向对象的程序设计思想是什么 我翻阅书籍 写下了这样一段话 就是警惕自己 如果未来被面试题面到 也能当做背诵个资料来看 下面开始简述那段话 文章目录 1 简述 面向对象的
  • PDM信号与PCM信号

    总结一下PDM信号与PCM信号 PDM PDM 脉冲密度调制 模拟信号的幅值使用输出脉冲对应区域的密度表示 PWM波是PDM波转换频率固定的一种特例 在实际输出的一位数据流中 只存在 1 和 0 1的密度越大 代表该区域对应的模拟信号幅值越
  • sql 2000 分页

    create PROCEDURE dbo Proc GetPageList Tables varchar 1000 表名 PK varchar 100 主键 Fields varchar 1000 查询的字段 SortField varch
  • 一阶RC滤波器

    一阶RC滤波器 作者 AirCity 2020 2 6 Aircity007 sina com 本文所有权归作者Aircity所有 RC低通滤波器 频响曲线 幅度下降到Ui 2 即是3dB带宽 此时 CR 1 2 f 1 CR f 1 2
  • SLF4J: Class path contains multiple SLF4J bindings.

    springboot启动出现如下警告 SLF4J Class path contains multiple SLF4J bindings SLF4J Found binding in jar file C Users wangfei m2
  • Python做数据分析需要学什么?

    下面分别从这四个方面来带大家学习数据分析 第一 做数据分析要精通Python吗 第二 数据分析流程是什么 学什么 第三 如何培养数据分析思维 第四 数据分析书籍推荐 一 数据分析要精通Python吗 做数据分析不必精通Python 但至少要
  • C++11类型转换总结

    一 强制类型转换 用C 中的四个强制类型转换的关键字 static cast const cast reinterpret cast dynamic cast static cast lt 类型说明符 gt 表达式 dynamic cast
  • docker进入容器出现bash-4.2#解决办法

    docker进入容器显示bash 4 2 如下 root VM 4 15 centos shopmall docker exec it u root 1f654abf60ac bash bash 4 2 出现上述问题是因为在 root 目录
  • go语言标准库

    在Go语言的安装文件里包含了一些可以直接使用的包 即标准库 Go语言的标准库 通常被称为语言自带的电池 提供了清晰的构建模块和公共接口 包含 I O 操作 文本处理 图像 密码学 网络和分布式应用程序等 并支持许多标准化的文件格式和编解码协
  • Linux 系统常用命令

    Linux 系统常用命令格式 command option argument1 argument2 其中option以 开始 多个option可用一个 连起来 如 ls l a 与 ls la 的效果是一样的 根据命令的不同 参数分为可选的

随机推荐

  • Centos设置屏幕不休眠

    前言 前段时间因工作需要 安装了一个centos7虚拟机体验了一把linux编程 感觉有些情况下比在windows中开发方便许多 囧 期间遇到一小问题 就是虚拟机每隔几分钟不操作 则会自动进入屏幕保护 需要重新输入密码才能进入 为此查了一下
  • 删除卷与分页文件(虚拟内存文件)

    无法删除卷可能是由于这个磁盘中存在分页文件 虚拟内存文件 引起的
  • Tomcat优化大全,进来看了,真就会了

    前言 Tomcat 服务器是一个开源的轻量级Web应用服务器 在中小型系统和并发量小的场合下被普遍使用 是开发和调试Servlet JSP 程序的首选 相信大家对于 Tomcat 已经是非常熟悉了 本篇将介绍tomcat的常见优化 那么为什
  • 网络设备网卡、中继器、集线器、网桥、交换机、路由器工作原理

    b 网络设备网卡 中继器 集线器 网桥 交换机 路由器工作原理 b b 网卡 b 1 工作在物理层 进行数据接收和发送 b 中继器 b 1 工作在物理层 用来复原网络中的信号并重新发送到其他网段上 进行数据接收再发送 b 集线器 b 1 工
  • echarts tooltip文字太长换行

    tooltip文字太长换行 设置了宽度也没有换行 加上一句 extraCssText max width 300px white space pre wrap 没加之前是这样 加上之后 extraCssText max width 300p
  • Tomcat8安装及配置详解

    Tomcat8安装及配置详解 1 下载安装包 2 安装Tomcat8 下载的zip包为免安装版 解压后可直接使用 3 配置环境变量 4 运行命令 5 测试是否成功 1 下载安装包 访问Tomcat官网https tomcat apache
  • Unity中协程(IEnumerator)的使用方法介绍

    在Unity中 一般的方法都是顺序执行的 一般的方法也都是在一帧中执行完毕的 当我们所写的方法需要耗费一定时间时 便会出现帧率下降 画面卡顿的现象 当我们调用一个方法想要让一个物体缓慢消失时 除了在Update中执行相关操作外 Unity还
  • MacOS Excel 科研作图示例

    系统版本 MacOS Catalina Excel版本 Excel for Mac 2019 效果图如下 介绍一下源数据 共有2种电极 分别用方法1与方法2处理而得 将这些电极分别用3种biomarker进行特异性实验 获得数据如下图 首先
  • RFID技术在机场行李自动分拣系统中的应用—铨顺宏

    RFID技术在机场行李自动分拣系统中的应用 1 社会背景 科技改变世界的工作方式 随着全球经济的迅猛发展 全世界范围内的贸易量不断加大 对整个的物流行业提出了更高的要求 机场行李自动分拣系统作为现代物流中的一个重要组成部分 同样面临着严峻的
  • 那些年,我们一起误解过的REST

    欢迎大家前往腾讯云 社区 获取更多腾讯海量技术实践干货哦 本文由sammyshen 发表于云 社区专栏 最近几年REST API越来越流行 特别是随着微服务的概念被广泛接受和应用 很多Web Service都使用了REST API REST
  • Python 入門語法和類型

    Python 入門語法和類型
  • MYSQL实现Oracle函数 over (partition by ...order by ...)

    mysql是没有oracle的这个分析函数 故只能自然根据原有语法写 先创建一个测试数据库 如图 要实现根据组别gid按num排序后重新获取列表 理论上就是自联表 把num比自己大的或者比自己小的作为临时表 代码如下 SELECT t CO
  • SAP MM ME2M ME2L ME28 增强自定义字段

    本人诚心接ABAP远程开发任务 价格公道 有需要的联系我 欢迎个人 甲方爸爸 乙方私信联系 目前项目需要增强ME2L 去增加客制化的字段 一开始顾问要求是copy标准程序 然后增加字段 查阅资料之后发现 SAP 预留了标准的增强出口去做增强
  • 计算共形几何 pdf_几何着色器

    几何着色器概述 Introduction PDF下载地址传送positiveczp github io positiveczp github io 25E5 2587 25A0 25E4 25BD 2595 25E7 259D 2580 2
  • Unity制作地震防空知识视频讲解程序

    https www bilibili com video BV1Hy4y1S78b 定制访问 https item taobao com item htm spm a2oq0 12575281 0 0 50111debJplIKu ft t
  • 技术人再不懂区块链,你就OUT了?漫画版

    这几天区块链技术无意中被徐小平 忽悠 的更加红火了 蹭着区块链的大火 今天小编就再给大家普及一下区块链相关知识 一幅漫画秒懂 区块链 区块链技术是指一种全民参与记账的方式 所有的系统背后都有一个数据库 你可以把数据库看成是一个大账本 目前是
  • 【MATLAB第60期】【更新中】基于MATLAB的ARMAX具有外生回归因子的移动平均自回归模型

    MATLAB第60期 更新中 基于MATLAB的ARMAX具有外生回归因子的移动平均自回归模型 版本更新 2023 7 29版本 1 增加自定义参数 方便直接套数据运行 pre num 3 预采样数据个数 learn pr 0 85 训练数
  • 【Antlr】WHITESPACE is not a recognized channel name

    1 背景 antlr4 权威指南中的文件 第十二章 Simple statically typed programming language with functions and variables taken from Language
  • 51单片机 并行I/O端口介绍

    在51单片机中 共有32只I O引脚 分属于4个端口 P0 P3 端口的功能介绍 1 可作为并行I O输入通道 例如按键开关连接通路 图中P1端口的作用便是作为并行I O输入通道 2 可作为并行I O输出通道 例如 数码显示器 图中P2端口
  • 重写equals()方法

    1 如果想把持久类的实例放入set中 多值关联时 1对多 建议实现equals和hashcode2 想重用托管实例时 也要实现equals和hashcode 3 多个字段组合作为联合主键 必须实现equals和hashcode方法 equa