博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
为什么重写equals方法时,要求必须重写hashCode方法?
阅读量:5134 次
发布时间:2019-06-13

本文共 3162 字,大约阅读时间需要 10 分钟。

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方法

1 class Test 2 { 3     private int num; 4     private String data; 5  6     public boolean equals(Object obj) 7     { 8         if (this == obj) 9             return true;10 11         if ((obj == null) || (obj.getClass() != this.getClass()))12             return false;13 14         //能执行到这里,说明obj和this同类且非null。15         Test test = (Test) obj;16         return num == test.num&& (data == test.data || (data != null && data.equals(test.data)));17     }18 19     public int hashCode()20     {21         //重写equals,也必须重写hashCode。具体后面介绍。22     }23 24 }

 

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
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

转载于:https://www.cnblogs.com/ouym/p/8963219.html

你可能感兴趣的文章
aboutMe
查看>>
【Debug】IAR在线调试时报错,Warning: Stack pointer is setup to incorrect alignmentStack,芯片使用STM32F103ZET6...
查看>>
一句话说清分布式锁,进程锁,线程锁
查看>>
FastDFS使用
查看>>
服务器解析请求的基本原理
查看>>
[HDU3683 Gomoku]
查看>>
下一代操作系统与软件
查看>>
Python IO模型
查看>>
DataGridView的行的字体颜色变化
查看>>
局域网内手机访问电脑网站注意几点
查看>>
[Serializable]的应用--注册码的生成,加密和验证
查看>>
Android-多线程AsyncTask
查看>>
LeetCode【709. 转换成小写字母】
查看>>
CF992E Nastya and King-Shamans(线段树二分+思维)
查看>>
如果没有按照正常的先装iis后装.net的顺序,可以使用此命令重新注册一下:
查看>>
linux install ftp server
查看>>
alter database databasename set single_user with rollback IMMEDIATE 不成功问题
查看>>
【题解】青蛙的约会
查看>>
autopep8
查看>>
GIT在Linux上的安装和使用简介
查看>>