如何正确的覆盖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.对于对象中每个关键域 ...
随机推荐
- MyEclipse项目里面出现红叉的解决方案?
一般出现在从别处import的项目上,只有项目文件夹上有红叉,其他地方都正常,现总结个人的几个解决方案: 有几种可能: 1,编码设置是否一致,也即是你项目原来的编码和现在eclipse用的默认编码 ...
- 第三个Sprint冲刺第5天
成员:罗凯旋.罗林杰.吴伟锋.黎文衷 各成员努力完成最后冲刺
- shell脚本--shift参数左移
参数左移什么意思呢?这个参数指的是在运行脚本时,跟在脚本名后面的参数,前面已经讲过,可以使用$#来获取参数的个数,使用$*来获取所有的参数,而参数左移的含义是这样的:有个指针指向参数列表第一个参数,左 ...
- HDU 2032 杨辉三角
http://acm.hdu.edu.cn/showproblem.php?pid=2032 Problem Description 还记得中学时候学过的杨辉三角吗?具体的定义这里不再描述,你可以参考 ...
- Qt__状态栏(statusBar)
转自豆子空间 状态栏位于主窗口的最下方,提供一个显示工具提示等信息的地方.一般地,当窗口不是最大化的时候,状态栏的右下角会有一个可以调节大小的控制点:当窗口最大化的时候,这个控制点会自动消失.Qt提供 ...
- eclipse里面找不到databaseexplorer
在window==>show view==>Other==>Data Management==>Database explorer配置:在右下方点击Database Sourc ...
- RabbitMQ基础知识详解
什么是MQ? MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法.MQ是消费-生产者模型的一个典型的代表,一端往消息队列中不断写入消息,而另一端则可以读取队列中 ...
- linux利用CMakeLists编译程序或生成库文件
#设置CMAKE最低版本 CMAKE_MINIMUM_REQUIRED(VERSION 2.8) #设置项目名称 SET(PROJECT_NAME Image_Test_01) #建立项目 PROJE ...
- 训练题(代码未检验)(序列前k大和问题)
大厦 Time Limit : 4000/2000ms (Java/Other) Memory Limit : 65535/32768K (Java/Other) Total Submission ...
- BZOJ1283 序列(费用流)
不妨看做是先用k个指针指向被选择的前k个元素,然后每次将选中当前第一个元素的指针移到最后,并且需要满足位置变化量>=m.显然这样可以构造出所有的合法方案.那么可以以此建立费用流模型,以一条流量k ...