关于覆写equals与hashCode的问题。
来源:互联网 发布:陕西网络广告公司 编辑:程序博客网 时间:2024/05/17 07:22
对于hash code的理论我不想多说,这个话题太大。那些“对称性”,“传递性”的规则网上有无数的文章来描述。我只想说用hash code的原因只有一个:效率。理论的说法它的复杂度只有O(1)。试想我们把元素放在线性表里面,每次要找一个元素必须从头一个一个的找它的复杂度有O(n)。如果放在平衡二叉树,复杂度也有O(log n)。
为啥很多地方说“覆写equals的时候一定要覆写hashCode”。说到这里我知道很多人知道有个原则:如果a.equals(b)那么要确保a.hashCode()==b.hashCode()。为什么?hashCode和我写的程序的业务逻辑毫无关系,为啥我要override? 要我说如果你的class永远不可能放在hash code为基础的容器内,不必劳神,您真的不必override hashCode() :)
说得准确一点放在HashMap和Hashtable里面如果是作为value而不是作为key的话也是不必override hashCode了。至于HashSet,实际上它只是忽略value的HashMap,每次HashSet.add(o)其实就是HashMap.put(o, dummyObject)。
那为什么放到Hash容器里面要overide hashCode呢?因为每次get的时候HashMap既要看equals是不是true也要看hash code是不是一致,put的时候也是要看equals和hash code。
如果说到这里您还是不太明白,咱就举个例子:
譬如把一个自己定义的class Foo{...}作为key放到HashMap。实际上HashMap也是把数据存在一个数组里面,所以在put函数里面,HashMap会调Foo.hashCode()算出作为这个元素在数组里面的下标,然后把key和value封装成一个对象放到数组。等一下,万一2个对象算出来的hash code一样怎么办?会不会冲掉?先回答第2个问题,会不会冲掉就要看Foo.equals()了,如果equals()也是true那就要冲掉了。万一是false,就是所谓的collision了。当2个元素hashCode一样但是equals为false的时候,那个HashMap里面的数组的这个元素就变成了链表。也就是hash code一样的元素在一个链表里面,链表的头在那个数组里面。
回过来说get的时候,HashMap也先调key.hashCode()算出数组下标,然后看equals如果是true就是找到了,所以就涉及了equals。
假设如果有个key为a的元素在HashMap里面的情况:
1:如果这时候用equals为true但是hashCode不等的b作为get参数的话,这个时候b算出来的数组下标一定不是a所在的下标位置。
2:如果这时候用equals为false但是hashCode相等的b作为get参数的话,这个时候b算出来的数组下标是对了,但是用equals来寻找相符的key就找不到a了。
以上2种情况要么就是get找不到符合的元素返回null,要么就是返回一个hashCode和equals恰好都符合b的另外的元素,这就产生了混乱。混乱的根本就是错误实现hashCode和equals。
下面有个非常简化版的HashMap实现帮助大家理解,您甚至可以把它当作伪代码来看。(这个实现只是为了模拟HashMap的机制,所以参数检查,访问修饰符都忽略。在Java.util.HashMap里面的对hash值的二次hash,根据数组长度计算index,以及超出数组时的resize都忽略)
/* * Just to demonstrate hash map mechanism, * Please do not use it in your commercial product. * * Argument checking and modifier are ignored. * In java.util.HashMap, array are used instead of ArrayList, so index of array is calculated by 'h & (length-1)', * while we use ArrayList to skip the calculation for simple. * * @author Shengyuan Lu 卢声远 <michaellufhl@yahoo.com.cn> */ public class SimpleHashMap { ArrayList<LinkedList<Entry>> entries = new ArrayList<LinkedList<Entry>>(); /** * Each key-value is encapsulated by Entry. */ static class Entry { Object key; Object value; public Entry(Object key, Object value) { this.key = key; this.value = value; } } void put(Object key, Object value) { LinkedList<Entry> e = entries.get(key.hashCode()); if (e != null) { for (Entry entry : e) { if (entry.key.equals(key)) { entry.value = value;// Match in lined list return; } } e.addFirst(new Entry(key, value));// Add the entry to the list } else { // Put the new entry in array LinkedList<Entry> newEntry = new LinkedList<Entry>(); newEntry.add(new Entry(key, value)); entries.add(key.hashCode(), newEntry); } } Object get(Object key) { LinkedList<Entry> e = entries.get(key.hashCode()); if (e != null) { for (Entry entry : e) { if (entry.key.equals(key)) { return entry.value; } } } return null; } /** * Do we need to override equals() and hashCode() for SimpleHashMap itself? * I don't know either:) */ }
- 关于覆写equals与hashCode的问题。
- hashCode()和equals()的覆写问题
- 关于hashCode与equals
- Java中hashCode()与equals()的问题
- java解惑之重载与覆写(equals与hashCode) .
- 为什么覆写equals的时候一定要覆写hashCode?
- 为什么覆写equals的时候一定要覆写hashCode
- 为什么覆写equals的时候一定要覆写hashCode
- 为什么覆写equals的时候一定要覆写hashCode?
- 为什么覆写equals的时候一定要覆写hashCode?
- 为什么覆写equals的时候一定要覆写hashCode?
- 为什么覆写equals的时候一定要覆写hashCode?
- 为什么覆写equals的时候一定要覆写hashCode?
- 为什么覆写equals的时候一定要覆写hashCode?
- 关于java中hashCode与equals为什么一起重写的问题
- 什么时候 hashCode() 与 equals() 应该同时覆写!
- hashtable里面关于equals和hashcode的覆盖重写问题
- 关于hashCode()与equals()的总结,所要知道的
- 设置渐变背景色
- Myeclipse2014 SVN在线安装方法
- spring事务
- android二维码扫描 Zxing 3.X 使用与开启闪关灯
- 第1章 简单工厂模式
- 关于覆写equals与hashCode的问题。
- symfony学习笔记20170117
- 游戏过关
- 剑指offer-面试题7-用两个栈实现队列
- 前端优化之前端工程化
- 登录验证
- 360 mysql-atlas
- 轮播图
- Linux.修改文件权限