为什么要重写hashCode和equals方法
1 复习一下Hash算法
先复习一下数据结构里的一个知识点:在一个长度为 n
(假设是 10000
)的线性表(假设是ArrayList)里,存放着无序的数字;如果我们要找一个指定的数字,就不得不通过从头到尾依次遍历来查找。
我们再来观察Hash表(这里的Hash表纯粹是数据结构上的概念,和Java无关)。它的平均查找次数接近于 1
,代价相当小,关键是在Hash表里,存放在其中的数据和它的存储位置是用Hash函数关联的。
我们假设一个Hash函数是 x*x%5
。当然实际情况里不可能用这么简单的Hash函数,这里纯粹为了说明方便,而Hash表是一个长度是 11
的线性表。如果我们要把 6
放入其中,那么我们首先会对 6
用Hash函数计算一下,结果是 1
,所以我们就把 6
放入到索引号是 1
这个位置。同样如果我们要放数字 7
,经过Hash函数计算, 7
的结果是 4
,那么它将被放入索引是4
的这个位置。这个效果如下图所示。
这样做的好处非常明显。比如我们要从中找 6
这个元素,我们可以先通过Hash函数计算 6
的索引位置,然后直接从 1
号索引里找到它了。
不过我们会遇到“Hash值冲突”这个问题。比如经过Hash函数计算后, 7
和 8
会有相同的Hash值,对此Java的HashMap对象采用的是**“链地址法”**的解决方案。效果如下图所示
具体的做法是,为所有Hash值是 i
的对象建立一个同义词链表。假设我们在放入 8
的时候,发现 4
号位置已经被占,那么就会新建一个链表结点放入 8
。同样,如果我们要找 8
,那么发现 4
号索引里不是 8
,那会沿着链表依次查找。
虽然我们还是无法彻底避免Hash值冲突的问题,但是Hash函数设计合理,仍能保证同义词链表的长度被控制在一个合理的范围里。这里讲的理论知识并非无的放矢,大家能在后文里清晰地了解到重写hashCode方法的重要性。
2 复习Object类的hashCode和equals方法
class User{
String username;
String pwd;
public User(String username, String pwd) {
super();
this.username = username;
this.pwd = pwd;
}
}
public class Test {
public static void main(String[] args) {
User user1=new User("admin"