如何正确的覆盖equals和hashCode
一、Object所有的非final方法
- public boolean equals(Object obj)
- public native int hashCode()
- public String toString()
- protected native Object clone() throws CloneNotSupportedException
- protected void finalize() throws Throwable { }
类的方法前加final关键字,说明该方法不能被该类的子类重写。
二、equals方法和hashCode方法
1、什么时候需要覆盖equals方法
如果类具有自己特有的“逻辑相等”概念(不同于对象等同的概念),而且超类还没有覆盖equals以实现期望的行为,这时候我们就需要覆盖equals方法。
2、如何正确的覆盖equals方法
equals方法实现了等价关系:自反性,对称性,传递性,一致性,非空性(x.equals(null)返回为false)
- 使用==操作符检查“参数是否为这个对象的引用”,如果是,则返回true。
- 使用instanceof操作符检查“参数是否为正确的类型”,如果不是,则返回false。
- 把参数转换成正确的类型。
- 对于该类中的每个“关键”阈,检查参数中的阈是否与该对象中对应的阈相匹配。
class Student{ private String name;
private int age;
private double height;
@Override
public boolean equals(Object obj) {
//使用==操作符检查“参数是否为这个对象的引用”
if(this==obj)
return true;
//使用instanceof操作符检查“参数是否为正确的类型”
if(!(obj instanceof Student))
return false;
//把参数转换成正确的类型。
Student student=(Student) obj;
//对于该类中的每个“关键”阈,检查参数中的阈是否与该对象中对应的阈相匹配。
return this.name==student.name && this.age==student.age && this.height==student.height;
}
}
1、编写完成equals方法之后,应该问自己三个问题:它是否对称的、传递的、一致的。
2、不要将equals声明中的Object对象替换为其他的类型
public boolean equals(Student obj)
这样相当于重载了equals方法,而非是覆盖。
3、覆盖equals时总要覆盖hashCode
HashCode有一条约定如下:
如果两个对象根据equals(Object)方法比较是相等,那么调用这两个对象中任意一个对象的hashCode方法都必须产生同样的整数结果。
下面给出一种简单的解决办法:
- 把某个非零的常数值,比如说17,保存在一个名为result的int类型的变量中。
- 对于对象每个关键域f(指equals方法中涉及的每个域),完成以下步骤:
- 如果该域是boolean类型,则计算(f ? 1 : 0)。
private boolean flag=true;
int boolTemp=flag?0:1; - 如果该域是byte、char、short或者int类型,则计算(int)f。
- 如果该域是float类型,则计算Float.floatToIntBit(f)。
- 如果该域是long类型,则计算(int)(f ^ (f >>> 32))。
- 如果该域是double类型
private double height;
long heightBits=Double.doubleToLongBits(height);
int heightTemp=(int)(heightBits ^ (heightBits >>> 32)); - 如果该域是一个对象引用,并且该类的equals方法通过递归调用equals的方式来比较这个域,则同样为这个域递归调用hashCode。
private String name;
int stringTemp=this.name.hashCode();
完整的Student类:
class Student{
private String name;
private int age;
private double height;
@Override
public boolean equals(Object obj) {
//使用==操作符检查“参数是否为这个对象的引用”
if(this==obj)
return true;
//使用instanceof操作符检查“参数是否为正确的类型”
if(!(obj instanceof Student))
return false;
//把参数转换成正确的类型。
Student student=(Student) obj;
//对于该类中的每个“关键”阈,检查参数中的阈是否与该对象中对应的阈相匹配。
return this.name==student.name && this.age==student.age && this.height==student.height;
} @Override
public int hashCode() {
//初始化
int result=17;
//String类型
result=this.name.hashCode()+result;
//int类型
result=this.age+result;
//double类型
long heightBits=Double.doubleToLongBits(height);
int heightTemp=(int)(heightBits ^ (heightBits >>> 32));
result=heightTemp+result;
//返回
return result;
}
}
如何正确的覆盖equals和hashCode的更多相关文章
- 如何正确的重写equals() 和 hashCode()方法
比较两个Java对象时, 我们需要覆盖equals和 hashCode. public class User{ private String name; private int age; priva ...
- Java提高篇——equals()与hashCode()方法详解
java.lang.Object类中有两个非常重要的方法: 1 2 public boolean equals(Object obj) public int hashCode() Object类是类继 ...
- 大杂烩 -- equals、hashCode联系与区别
基础大杂烩 -- 目录 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- Equals 1.默认情况(没有覆盖equals方 ...
- 集合框架比较两个对象是否相同(equals和hashCode方法)
package com.dcz.hashset; import java.util.HashSet; import java.util.Set; /** * HashSet是接口最常用的实现类,顾名思 ...
- 【Java实战】源码解析为什么覆盖equals方法时总要覆盖hashCode方法
1.背景知识 本文代码基于jdk1.8分析,<Java编程思想>中有如下描述: 另外再看下Object.java对hashCode()方法的说明: /** * Returns a hash ...
- 第9条:覆盖equals时总要覆盖hashCode
在每个覆盖equals方法的类中,也必须覆盖hashCode方法.否则,会违反Object.hashCode的通用约定,从而导致该类无法结合所有基于散列的集合一起正常工作,包括HashMap,Hash ...
- 覆盖equals的时候总要覆盖hashCode
import java.util.HashMap; public class Student { private String name ; private String id; public Stu ...
- Item 9 覆盖equals时总要覆盖hashCode
为什么覆盖equals时,总要覆盖hashCode? 原因是,根据Object规范: 如果两个对象根据equals(Object)方法比较是相等的,那么调用这两个对象中任意一个对象的hashCod ...
- EffectiveJava(9)覆盖equals是总要覆盖hashCode
覆盖equals是总要覆盖hashCode 通过散列函数将集合中不相等的实例均匀的分布在所有可能的散列值上 1.把某个非零的常数值保存在一个名为result的int类型变量中 2.对于对象中每个关键域 ...
随机推荐
- 递归拼装Tree结构数据
@Override public List<Map<String, Object>> queryListTree() { List<Map<String,Objec ...
- PAT 甲级 1135 Is It A Red-Black Tree
https://pintia.cn/problem-sets/994805342720868352/problems/994805346063728640 There is a kind of bal ...
- jeecg 主-附表生成代码例子
jeecg 主-附表生成代码例子 - CSDN博客https://blog.csdn.net/u010411264/article/details/51243277 JEECG Online Codi ...
- JDK学习AbstractQueuedSynchronizer和AbstractQueuedLongSynchronizer
AbstractQueuedLongSynchronizer类是扩展自AbstractQueuedSynchronizer的,实现了java.io.Serializable接口. 其中提到的wait ...
- [转帖]/etc/security/limits.conf的含义
https://www.cnblogs.com/pzk7788/p/7250723.html /etc/security/limits.conf 是 Linux 资源使用配置文件,用来限制用户对系统资 ...
- linux_目录基本操作
ls命令 ls命令用来显示目标列表,在Linux中是使用率较高的命令.ls命令的输出信息可以进行彩色加亮显示,以分区不同类型的文件. 语法 $ ls [选项] [目录] 选项 说明 -a 显示所有档案 ...
- CentOS 安全优化
1.操作系统和数据库系统管理用户身份鉴别信息令应有复杂度要求并定期更换. 配置# vi /etc/login.defs 系统默认配置: PASS_MIN_LEN=5 #密码最小长度 PASS_MAX_ ...
- 洛谷 P4878 [USACO05DEC]layout布局
题面链接 sol:差分约束系统裸题,根据a+b<=c建个图跑个最短路就没了... #include <queue> #include <cstdio> #include ...
- 用DBContext (EF) 实现通用增删改查的REST方法
我们用ADO.NET Entity Data Model来生成实体类后,一般都会对这些类进行基本的增删改查操作,如果每个类都要写这些基本的方法,实在太乏味了.下面就是通过step by step的方式 ...
- pyinstaller模块使用
目前pip install pyinstaller已经成熟 但是还是有一些坑,郁闷了好久,记一下注意点吧. 将py脚本打包成exe文件时,如果导入了非python自带库,则需要将导入的库从site-p ...