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. [Codeforces Round #513 by Barcelona Bootcamp (rated, Div. 1 + Div. 2) ](A~E)

    A: 题目大意:给你一个数字串,每个数字只可以用一次,求最多可以组成多少个电话号码(可以相同),电话号码第一个数字为$8$,且长度为$11$ 题解:限制为$8$的个数和总长度,直接求 卡点:无 C++ ...

  2. [AT2698] Don't Be a Subsequence

    题目大意:给定一个字符串,求一个最短的串要求没有在该字符串的子串中出现过,如果有多个,输出字典序最小的那一个. 题解:倒着跑一遍原字符串(以下编号为$1\sim n$),按出现了所有$26$个字母来分 ...

  3. Codeforces Round #328 (Div. 2) C 数学

    C. The Big Race time limit per test 1 second memory limit per test 256 megabytes input standard inpu ...

  4. poj 2367 拓扑排序入门

    Description The system of Martians' blood relations is confusing enough. Actually, Martians bud when ...

  5. (转)HTML5 本地数据库(SQLite) 示例

      HTML5 本地数据库(SQLite) 示例 2012-05-07 16:21:13 标签:SQLite HTML5本地数据库 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作 ...

  6. 解析Linux内核的基本的模块管理与时间管理操作---超时处理【转】

    转自:http://www.jb51.net/article/79960.htm 这篇文章主要介绍了Linux内核的基本的模块管理与时间管理操作,包括模块加载卸载函数的使用和定时器的用法等知识,需要的 ...

  7. wchar_t类型的几个函数

    wchar_t是C/C++的字符数据类型,是一种扩展的字符存储方式. 在Windows下,wchar_t占2个字节(byte):在Linux下,wchar_t占4个字节 wchar_t类型主要用在国际 ...

  8. jQuery简单操作HTML的DOM

    #转载请留言联系 如果需要了解什么是HTML的dom,可以参考:http://www.w3school.com.cn/htmldom/index.asp 下面的是jQuery操作DOM,并不是Java ...

  9. 51nod 1413 权势二进制【进制思维】

    1413 权势二进制 题目来源: CodeForces 基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题  收藏  关注 一个十进制整数被叫做权势二进制,当他的十进制 ...

  10. 宠物收养所 (SBT)

    宠物收养所 最近,阿Q开了一间宠物收养所.收养所提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物.每个领养者都希望领养到自己满意的宠物,阿Q根据领养者的要求通过他自己发明的一个特殊的公式,得 ...