要理解hashcode首先要理解hash表这个概念
Java的基类Object中的 equals()方法用于判断两个对象是否相等,hashCode()方法用于计算对象的哈希码。equals()和hashCode()都不是final方法,都可以被重写(overwrite)
Object类中equals()方法实现如下
public boolean equals(Object obj) {
return (this == obj);
}
通过该实现可以看出,Object类的实现采用了区分度最高的算法,即只要两个对象不是同一个对象,那么equals()一定返回false。
虽然可以重写equals()方法,但是有一些注意事项;JDK中说明了实现equals()方法应该遵守的约定
Object类中hashCode()方法的声明如下:
public native int hashCode();
可以看出,hashCode()是一个native方法,而且返回值类型是整形;实际上,该native方法将对象在内存中的地址作为哈希码返回,可以保证不同对象的返回值不同。
与equals()方法类似,hashCode()方法可以被重写。JDK中对hashCode()方法的作用,以及实现时的注意事项做了说明:
重写hashcode()的原则
hashCode()重写方法
《Effective Java》中提出了一种简单通用的hashCode算法:
初始化一个整形变量,为此变量赋予一个非零的常数值,比如int result = 17;
选取equals方法中用于比较的所有域(之所以只选择equals()中使用的域,是为了保证上述原则的第1条),然后针对每个域的属性进行计算:
(1) 如果是boolean值,则计算f ? 1:0
(2) 如果是bytecharshortint,则计算(int)f
(3) 如果是long值,则计算(int)(f ^ (f >>> 32))
(4) 如果是float值,则计算Float.floatToIntBits(f)
(5) 如果是double值,则计算Double.doubleToLongBits(f),然后返回的结果是long,再用规则(3)去处理long,得到int
(6) 如果是对象应用,如果equals方法中采取递归调用的比较方式,那么hashCode中同样采取递归调用hashCode的方式。否则需要为这个域计算一个范式,比如当这个域的值为null的时候,那么hashCode 值为0
(7) 如果是数组,那么需要为每个元素当做单独的域来处理。java.util.Arrays.hashCode方法包含了8种基本类型数组和引用数组的hashCode计算,算法同上。
最后,把每个域的散列码合并到对象的哈希码中。
HashMap中并没有直接使用KV中K原有的hash值; 在HashMap的put、get操作时也未直接使用K中原有的hash值,而使用了一个hash()方法。让我们一起看一下这个方法
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
这段代码类似作用是为了增加hashcode的随机性
key.hashCode()的作用是返回键值key所属类型自带的hashcode,返回int散列类型,如果直接拿散列值作为下标访问HashMap的主数组的话,考虑到int类型值的范围[-2^31 , 2^31 -1],虽然只要hash表映射比较松散的话,碰撞几率很小,但是映射空间太大,内存放不下,所以先做对数组的长度取模运算,得到的余数才能用来访问数组下标。
hashMap源码中模运算是在这个indexFor( )函数里完成的把散列值和数组长度-1做一个"与"操作
static int indexFor(int h, int length) {
return h & (length-1);
}
01111010 00111100 00100101
& 00000000 00000000 00001111
----------------------------------
00000000 00000000 00000101
//高位全部归零,只保留末四位
but 只取后四位,即使散列值分布再松散,碰撞几率还是很大。更糟糕的是如果散列函数做的比较差吧,分布上成个等差数列啥的,恰好使最后几个低位呈现规律性重复,就比较蛋疼。
这时候 “hash”函数作用就出来了
hashMap中 MAXIMUM_CAPACITY = 1 << 30;最大为2的30次方(超过这个值就将threshold修改为Integer.MAX_VALUE(此时桶大小已经是2的31次方了),表明不进行扩容了)
原文:https://www.cnblogs.com/NathanYang/p/9427456.html