1 equals方法

Object类中默认的实现方式是  :   return this == obj  。那就是说,只有this 和 obj引用同一个对象,才会返回true。

而我们往往需要用equals来判断 2个对象是否等价,而非验证他们的唯一性。这样我们在实现自己的类时,就要重写equals.

按照约定,equals要满足以下规则。

  • 自反性:  x.equals(x) 一定是true
  • 对null:  x.equals(null) 一定是false
  • 对称性:  x.equals(y)  和  y.equals(x)结果一致
  • 传递性:  a 和 b equals , b 和 c  equals,那么 a 和 c也一定equals。
  • 一致性:  在某个运行时期间,2个对象的状态的改变不会影响equals的决策结果,那么,在这个运行时期间,无论调用多少次equals,都返回相同的结果。

举例:重写equals方法

 class Test
{
private int num;
private String data; public boolean equals(Object obj)
{
if (this == obj)
return true; if ((obj == null) || (obj.getClass() != this.getClass()))
return false; //能执行到这里,说明obj和this同类且非null。
Test test = (Test) obj;
return num == test.num&& (data == test.data || (data != null && data.equals(test.data)));
} public int hashCode()
{
//重写equals,也必须重写hashCode。具体后面介绍。
} }

2 hashCode方法

这个方法返回对象的散列码,返回值是int类型的散列码。
对象的散列码是为了更好的支持基于哈希机制的Java集合类,例如 Hashtable, HashMap, HashSet 等。

关于hashCode方法,一致的约定是:

  • 在某个运行时期间,只要对象的(字段的)变化不会影响equals方法的决策结果,那么,在这个期间,无论调用多少次hashCode,都必须返回同一个散列码。
  • 如果2个对象通过equals调用后返回是true,那么这个2个对象的has
  • hCode方法也必须返回同样的int型散列码如果2个对象通过equals返回false,他们的hashCode返回的值允许相同。(然而,程序员必须意识到,hashCode返回独一无二的散列码,会让存储这个对象的hashtables更好地工作。)

重写了euqls方法的对象必须同时重写hashCode()方法。

3 为什么必须重写hashCode方法?

在上面的例子中,Test类对象有2个字段,num和data,这2个字段代表了对象的状态,他们也用在equals方法中作为评判的依据。那么, 在hashCode方法中,这2个字段也要参与hash值的运算,作为hash运算的中间参数。这点很关键,这是为了遵守:2个对象equals,那么 hashCode一定相同规则。

也是说,参与equals函数的字段,也必须都参与hashCode 的计算。

4 重写hashCode时注意事项

重写hashCode方法时除了上述一致性约定,还有以下几点需要注意:

(1)返回的hash值是int型的,防止溢出。

(2)不同的对象返回的hash值应该尽量不同。(为了hashMap等集合的效率问题)

(3)《Java编程思想》中提到一种情况

“设计hashCode()时最重要的因素就是:无论何时,对同一个对象调用hashCode()都应该产生同样的值。如果在讲一个对象用put()添加进HashMap时产生一个hashCdoe值,而用get()取出时却产生了另一个hashCode值,那么就无法获取该对象了。所以如果你的hashCode方法依赖于对象中易变的数据,用户就要当心了,因为此数据发生变化时,hashCode()方法就会生成一个不同的散列码”。

举个例子

public class Test {

    private int num;
private String data; public Test(int num,String data){
this.num = num;
this.data = data;
} public void setNum(int num) {
this.num = num;
} public boolean equals(Object obj)
{
if (this == obj)
return true; if ((obj == null) || (obj.getClass() != this.getClass()))
return false; Test test = (Test) obj;
return num == test.num&& (data == test.data || (data != null && data.equals(test.data)));
} public int hashCode()
{
int hash = 7;
hash = 31*hash+num;
hash = 31*hash+data.hashCode();
return hash; } public static void main(String[] args) { Map<Test,Integer> map = new HashMap<>();
Test t1 = new Test(21,"ouym");
map.put(t1, 1);
t1.setNum(20);
System.out.println(map.get(t1)); } }

输出值为null,我的天呐,hashMap取不到值了。

不重写equals和hashCode方法的话是不依赖于对象属性的变化的,也就是说这里使用默认的hashCode方法可以取到值。但是我们重写equal方法的初衷是判定name和num属性都相等的Test对象是相等的,而不是说同一个对象的引用才相等,而num=21和num=20明显不想等,所以这里hashCode返回值不同并不违背设计的初衷。注意上面代码的使用陷阱。

来自:https://www.cnblogs.com/lulipro/p/5628750.html

为什么重写equals方法时,要求必须重写hashCode方法?的更多相关文章

  1. 第九条:覆盖equals方法时总要覆盖hashCode方法

    Object类的hashCode方法: public native int hashCode();   是一个本地方法. 其中这个方法的主要注释如下: Whenever it is invoked o ...

  2. 【Java实战】源码解析为什么覆盖equals方法时总要覆盖hashCode方法

    1.背景知识 本文代码基于jdk1.8分析,<Java编程思想>中有如下描述: 另外再看下Object.java对hashCode()方法的说明: /** * Returns a hash ...

  3. 半夜思考, 为什么建议重写 equals() 方法时, 也要重写 hashCode() 方法

    我说的半夜, 并不是真正的半夜, 指的是在我一个人的时候, 我会去思考一些奇怪的问题. 要理解 hashCode() 需要理解下面三个点: hash契约 哈希冲突 哈希可变 第一点: hash 契约指 ...

  4. 覆写equals方法为什么需要覆写hashCode方法

    覆写equals方法必须覆写hashCode方法,是JDK API上反复说明的,不过为什么要这样做呢?这两个方法之间有什么关系呢? void test() { // Person类的实例作为Map的k ...

  5. 在IE浏览器中执行OpenFlashChart的reload方法时无法刷新的解决方法

    由于项目需求,需要在网页上利用图表展示相关数据的统计信息,采用了OpenFlashChart技术.OpenFlashChart是一款开源的以Flash和Javascript为技术基础的免费图表,用它能 ...

  6. 第八条——覆盖equals方法时需遵守的通用约定

    1)自反性 对于任何非null的引用值x,x.equals(x)必须返回true.---这一点基本上不会有啥问题 2)对称性 对于任何非null的引用值x和y,当且仅当x.equals(y)为true ...

  7. 为什么重写equals时必须重写hashCode方法?

    原文地址:http://www.cnblogs.com/shenliang123/archive/2012/04/16/2452206.html 首先我们先来看下String类的源码:可以发现Stri ...

  8. 为什么重写equals时必须重写hashCode方法?(转发+整理)

    为什么重写equals时必须重写hashCode方法? 原文地址:http://www.cnblogs.com/shenliang123/archive/2012/04/16/2452206.html ...

  9. Effective Java 第三版——11. 重写equals方法时同时也要重写hashcode方法

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  10. why在重写equals时还必须重写hashcode方法

    首先我们先来看下String类的源码:可以发现String是重写了Object类的equals方法的,并且也重写了hashcode方法 public boolean equals(Object anO ...

随机推荐

  1. GeoIP2 数据库更新地址

    GeoIP2 数据库更新地址 数据库文件下载网页地址 http://dev.maxmind.com/geoip/geoip2/geolite2/ http://geolite.maxmind.com/ ...

  2. 【ZBH选讲·模数和】

    [问题描述]你是能看到第二题的friends呢.——laekovHja和Yjq在玩游戏,这个游戏中Hja给了Yjq两个数,希望Yjq找到一些非负整数使得这些数的和等于n,并且所有数模maaaaaaaa ...

  3. Educational Codeforces Round 2 B. Queries about less or equal elements

    打开题目连接 题意:给2个数组(无序的)啊a,b,判断b数组中的每一个元素大于a数组中个数. ACcode: #include <iostream> #include <vector ...

  4. Android横竖屏总结(转)

    Android横竖屏总结(转) 横竖屏切换后Activity会重新执行onCreat函数,但是在Android工程的Mainfest.xml中加入android:screenOrientation=& ...

  5. OpenCV 2.4.9 学习笔记(2)—— OpenCV内存自动管理

    OpenCV自动内存管理 目前版本的OpenCV是自动处理所有自己的内存的,虽然这么说也不是很严谨.OpenCV在2.0版本中引入了一个新的C++接口,利用自动内存管理给出了解决问题的新方法.使用这个 ...

  6. 经典js框架

    http://requirejs.org/ http://durandaljs.com/ http://knockoutjs.com/index.html http://www.jeasyui.com ...

  7. JavaEE中Filter实现用户登录拦截

    实现思路是编写过滤器,如果用户登录之后session中会存一个user.如果未登录就为null,就可以通过过滤器将用户重定向到登陆页面,让用户进行登陆,当然过滤器得判断用户访问的如果是登陆请求需要放行 ...

  8. Python与数据结构[0] -> 链表/LinkedList[0] -> 单链表与带表头单链表的 Python 实现

    单链表 / Linked List 目录 单链表 带表头单链表 链表是一种基本的线性数据结构,在C语言中,这种数据结构通过指针实现,由于存储空间不要求连续性,因此插入和删除操作将变得十分快速.下面将利 ...

  9. TCP/IP,http,socket,长连接,短连接 —— 小结

    TCP/IP是什么? TCP/IP是个协议组,可分为三个层次:网络层.传输层和应用层.    在网络层有IP协议.ICMP协议.ARP协议.RARP协议和BOOTP协议.    在传输层中有TCP协议 ...

  10. luogu P1361 小M的作物

    题目链接 luogu P1361 小M的作物 题解 源汇点为A,B 向种子连边,容量为价值,每个种子能与A或B联通,考虑最小割 用建边的总流量减去最小割就是答案 相同利益的时候新建节点,由额外利益构成 ...