hashCode() 的做用是获取哈希码,也称为散列码;它其实是返回一个int整数。这个散列码的做用是肯定该对象在散列表中的索引位置,若是有看个人上一篇文章 什么是散列表,那么这里的散列码就至关于上文中根据首字母查询散列表例子中 人名关键字k在散列表中的具体地址。hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode() 函数。java
数组是java中效率最高的数据结构,可是“最高”是有前提的。第一咱们须要知道所查询数据的所在位置。第二:若是咱们进行迭代查找时,数据量必定要小,对于大数据量而言通常推荐集合。算法
在 Java 集合中有两类,一类是 List,一类是 Set 他们之间的区别就在于 List 集合中的元素师有序的,且能够重复,而 Set 集合中元素是无序不可重复的。对于 List 好处理,可是对于 Set 而言咱们要如何来保证元素不重复呢?经过迭代来 equals() 是否相等。数据量小还能够接受,当咱们的数据量大的时候效率可想而知(固然咱们能够利用算法进行优化)。好比咱们向 HashSet 插入 1000 数据,难道咱们真的要迭代 1000 次,调用 1000 次 equals() 方法吗?hashCode 提供了解决方案。怎么实现?咱们先看 hashCode 的源码(Object)。segmentfault
public native int hashCode();
它是一个本地方法,它的实现与本地机器有关。当咱们向一个集合中添加某个元素,集合会首先调用 hashCode 方法,这样就能够直接定位它所存储的位置,若该处没有其余元素,则直接保存。若该处已经有元素存在,就调用 equals 方法来匹配这两个元素是否相同,相同则不存,不一样则散列到其余位置。这样处理,当咱们存入大量元素时就能够大大减小调用 equals() 方法的次数,极大地提升了效率。数组
因此 hashCode 在上面扮演的角色为寻域(寻找某个对象在集合中区域位置)。hashCode 能够将集合分红若干个区域,每一个对象均可以计算出他们的 散列码,能够将 散列码分组,每一个分组对应着某个存储区域(散列表),根据一个对象的 散列码就能够肯定该对象所存储区域,这样就大大减小查询匹配元素的数量,提升了查询效率。缓存
hashCode 重要么?不重要,对于 List 集合、数组而言,可是对于 HashMap、HashSet、HashTable 而言,它变得异常重要。因此在使用 HashMap、HashSet、HashTable 时必定要注意 hashCode。对于一个对象而言,其 hashCode 过程就是一个简单的 Hash 算法的实现,其实现过程对你实现对象的存取过程起到很是重要的做用。数据结构
以 HashTable 为例阐述 hashCode 对于一个对象的重要性。函数
一个对象势必会存在若干个属性,如何选择属性来进行散列考验着一我的的设计能力。若是咱们将全部属性进行散列,这一定会是一个糟糕的设计,由于对象的 hashCode 方法无时无刻不是在被调用,若是太多的属性参与散列,那么须要的操做数时间将会大大增长,这将严重影响程序的性能。可是若是较少属相参与散列,散列的多样性会削弱,会产生大量的散列“冲突”,除了不可以很好的利用空间外,在某种程度也会影响对象的查询效率。其实这二者是一个矛盾体,散列的多样性会带来性能的下降。性能
那么如何对对象的 hashCode 进行设计,本人 也没有经验。从网上查到了这样一种解决方案:设置一个缓存标识来缓存当前的散列码,只有当参与散列的对象改变时才会从新计算,不然调用缓存的 hashCode,这样就能够从很大程度上提升性能。大数据
在 HashTable 计算某个对象在 table[] 数组中的索引位置,其代码以下:优化
int index = (hash & 0x7FFFFFFF) % tab.length;
为何要 &0x7FFFFFFF?由于某些对象的 hashCode 可能会为负值,与 0x7FFFFFFF 进行与运算能够确保 index 为一个正数。经过这步我能够直接定位某个对象的位置,因此从理论上来讲咱们是彻底能够利用 hashCode 直接定位对象的散列表中的位置,可是为何会存在一个 key-value 的键值对,利用 key 的 hashCode 来存入数据而不是直接存放 value 呢?这就关系 HashTable 性能问题的最重要的问题: Hash 冲突!(详见上篇)
咱们知道冲突的产生是因为不一样的对象产生了相同的散列码, hashcode 返回的是 int,它的值只可能在 int 范围内。若是咱们存放的数据超过了 int 的范围呢?这样就一定会产生两个相同的 散列码,这时在 散列码 位置处会存储两个对象,咱们就能够利用 key 自己来进行判断。因此具备相索引的对象,在该 散列码 位置处存在多个对象,咱们必须依靠 key 的 hashCode 和key 自己来进行区分。而Key的比较就用到了equals
简而言之就是:
对象的比较过程以下: