12、重写equals()为什么要重写hashCode()
大约 2 分钟
这是一个经常听到的话题,很多人都告诉我们,重写equals()一定要重写hashCode()。那么为什么一定要这么做,不这么做的后果是什么?
我们知道,equals()方法是用来判断两个对象的内容是否相同的。Object类中默认是比较两个对象的内存地址,我们可以根据自己的需要进行重写。
而hashCode()方法是用来继续一个对象的哈希值的,哈希值可以用来快速判断两个对象是否相同,Object类中默认实现是一个native方法。
使用hashCode最常见的场景,应该是HashMap和HashSet了。
我们知道,对于HashMap来说,它的key是不可以相同的,那么HashMap如何做到这一点的呢?它会有两个步骤:
- 首先,会计算key的哈希值,如果哈希不同,那么HashMap认为不是一个对象,可以插入
- 如果哈希值相同,HashMap会调用equals()方法来进一步判断两个对象是否相同,如果不同,仍然可以插入
这里我们就看出问题了,如果我们只重写equals()方法,不重写hashCode()方法,那么可能我们在equals()方法中认为是相同的对象,在hashCode()中可能是不同的,这样就会允许两个重复的键插入HashMap了。
综上,重写equals()方法一定要重写hashCode()方法。
实际上,在我的实际开发中,就遇到过一个例子,只不过有一点差别。
当时开发一个小窗程序,现在有小窗的应用信息和对应的一个窗口,我准备使用HashMap存储这个对应关系,小窗的应用信息作为key,窗口作为value。这样,就可以在创建好窗口时把这个窗口信息添加到Map中,在小窗关闭时根据应用信息释放掉这个窗口。
这一切看着都很好,可是,我发现,对于插入应用信息和窗口,我无法在小窗关闭时通过应用信息得到这个窗口,但是遍历Map时,这个窗口却实实在在的在Map中。
最终发现,我在执行中修改了一个应用信息的参数,因为我在equals()方法中并没有比较它,所以我忽略了它的存在,可是因为我没有重写