HashMap的很多函数要基于equal()函数和hashCode()函数。hashCode()用来定位要存放的位置,equal()用来判断是否相等。
那么,相等的概念是什么?
Object版本的equal只是简单地判断是不是同一个实例。但是有的时候,我们想要的的是逻辑上的相等。比如有一个学生类student,有一个属性studentID,只要studentID相等,不是同一个实例我们也认为是同一学生。当我们认为判定equals的相等应该是逻辑上的相等而不是只是判断是不是内存中的同一个东西的时候,就需要重写equal()。而涉及到HashMap的时候,重写了equals(),就需要重写hashCode()
我们总结一下几条基本原则
1. 同一个对象(没有发生过修改)无论何时调用hashCode()得到的返回值必须一样。
如果一个key对象在put的时候调用hashCode()决定了存放的位置,而在get的时候调用hashCode()得到了不一样的返回值,这个值映射到了一个和原来不一样的地方,那么肯定就找不到原来那个键值对了。
2. hashCode()的返回值相等的对象不一定相等,通过hashCode()和equals()必须能唯一确定一个对象
不相等的对象的hashCode()的结果可以相等。hashCode()在注意关注碰撞问题的时候,也要关注生成速度问题,完美hash不现实
3. 一旦重写了equals()函数(重写equals的时候还要注意要满足自反性、对称性、传递性、一致性),就必须重写hashCode()函数。而且hashCode()的生成哈希值的依据应该是equals()中用来比较是否相等的字段
如果两个由equals()规定相等的对象生成的hashCode不等,对于hashMap来说,他们很可能分别映射到不同位置,没有调用equals()比较是否相等的机会,两个实际上相等的对象可能被插入不同位置,出现错误。其他一些基于哈希方法的集合类可能也会有这个问题
通过hashCode和equals方法保证元素的唯一性,当重写equals方法时,必须重写hashCode方法,因为如果不重写这两个方法,就会默认使用Object的方法,一般是不相同的,所以就会导致存储了重复值,与hashset、hashmap等性质冲突。
哈希表判断通过hashCode和equals方法判断元素是否相同的步骤如下所示:
先看hashCode的值是否相同,因为这个是逻辑内存地址,如果
不相同:则表示对象不相同
如果相同:继续在桶结构中执行equals方法,equals方法返回
True:表示对象相同,
Fasle:表示对象不相同
只有hashCode和equals方法都返回true,才表示对象相同
hashcode这个方法是用来鉴定2个对象是否相等的。
那你会说,不是还有equals这个方法吗?
不错,这2个方法都是用来判断2个对象是否相等的。但是他们是有区别的。
一般来讲,equals这个方法是给用户调用的,如果你想判断2个对象是否相等,你可以重写equals方法,然后在代码中调用,就可以判断他们是否相等了。简单来讲,equals方法主要是用来判断从表面上看或者从内容上看,2个对象是不是相等。举个例子,有个学生类,属性只有姓名和性别,那么我们可以认为只要姓名和性别相等,那么就说这2个对象是相等的。
hashcode方法一般用户不会去调用,比如在hashmap中,由于key是不可以重复的,他在判断key是不是重复的时候就判断了hashcode这个方法,而且也用到了equals方法。这里不可以重复是说equals和hashcode只要有一个不等就可以了!所以简单来讲,hashcode相当于是一个对象的编码,就好像文件中的md5,他和equals不同就在于他返回的是int型的,比较起来不直观。我们一般在覆盖equals的同时也要覆盖hashcode,让他们的逻辑一致。举个例子,还是刚刚的例子,如果姓名和性别相等就算2个对象相等的话,那么hashcode的方法也要返回姓名的hashcode值加上性别的hashcode值,这样从逻辑上,他们就一致了。
要从物理上判断2个对象是否相等,用==就可以了。