总的来说,Java中的集合(Collection)有两类,一类是List,再有一类是Set。 前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。 那么这里就有一个比较严重的问题了:要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢? 这就是Object.equals方法了。但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。也就是说,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它就要调用1000次equals方法。这显然会大大降低效率。 此时hashCode方法的作用就体现出来了,当集合要添加新的对象时,先调用这个对象的hashCode方法,得到对应的hashcode值,实际上在HashMap的具体实现中会用一个table保存已经存进去的对象的hashcode值,如果table中没有该hashcode值,它就可以直接存进去,不用再进行任何比较了;如果存在该hashcode值, 就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址,所以这里存在一个冲突解决的问题,这样一来实际调用equals方法的次数就大大降低了,说通俗一点:Java中的hashCode方法就是根据一定的规则将与对象相关的信息(比如对象的存储地址,对象的字段等)映射成一个数值,这个数值称作为散列值。
在重写equals方法的同时,必须重写hashCode方法。默认情况下,hashCode方法是将对象的存储地址进行映射。
下面这段话摘自Effective Java一书:
在程序执行期间,只要equals方法的比较操作用到的信息没有被修改,那么对这同一个对象调用多次,hashCode方法必须始终如一地返回同一个整数。
如果两个对象根据equals方法比较是相等的,那么调用两个对象的hashCode方法必须返回相同的整数结果。
如果两个对象根据equals方法比较是不等的,则hashCode方法不一定得返回不同的整数。
对于第二条和第三条很好理解,但是第一条,很多时候就会忽略。在《Java编程思想》一书中的P495页也有同第一条类似的一段话:
“设计hashCode()时最重要的因素就是:无论何时,对同一个对象调用hashCode()都应该产生同样的值。如果在讲一个对象用put()添加进HashMap时产生一个hashCdoe值,而用get()取出时却产生了另一个hashCode值,那么就无法获取该对象了。所以如果你的hashCode方法依赖于对象中易变的数据,用户就要当心了,因为此数据发生变化时,hashCode()方法就会生成一个不同的散列码”。
- 参考资料
- 容器的实现
- ArrayList、LinkedList与Vector的区别
- Map,Set,List,Queue,Stack的特点与用法
- HashMap的实现
- HashMap和ConcurrentHashMap差别
- HashMap和HashTable的区别
- fast fail
- java 实用方法
- Collections中实用的函数
- ArrayList中实用的函数
- Integer和Character
- Properties类的简单使用
- XML实用解析
- 从jar包中读取文件信息
- java自带base64加密解密
- java机制
- 分派
- 反射
- 类加载机制
- java中一个对象的初始化
- 泛型
- 自动装箱,拆箱与遍历循环
- 偏向于语法
- new int[]
- new boolean[]
- Switch能否用string做参数
- equals与==的区别
- 泛型对象数组
- Enum的用法
- String、StringBuffer与StringBuilder的区别
- try catch finally
- finalize方法
- object有哪些公用方法
- Java的四种引用,强弱软虚,用到的场景
- java访问修饰符
- Hashcode的作用
- 九种基本数据类型
- java对象大小
- 数组长度
- 动态代理的一个例子
- java.lang.NoClassDefFoundError
- ThreadLocal