我们知道Objects定义了用于计算对象哈希值的hashcode ()函数。 而且很多类都复盖了hashcode ()函数。 但是,HashMap没有直接使用每个类的hash值,而是使用hash ()函数重新计算。
一.列举一些与基本类型对应的普通类型的hashcode ()
对象
publicstaticinthashcode (objecto ) (
返回o!=null? o.hashcode(:
}
智能手机
公共int hashcode (
returninteger.hashcode(value;
//是自己
斯汀
公共int hashcode (
int h=hash;
if(h==0value.length0) {
char val[]=value;
for(intI=0; i value.length; I ) {
h=31 * h val[i]; //
}
hash=h;
}
返回h;
//将字符串转换为字符数组,对字符的散列值进行的运算
角色
publicstaticinthashcode (char value ) {
返回(int )值;
//字符对应的asc11代码
日期
公共int hashcode (
long ht=this.getTime (;
return(int ) ht ^ (int ) ht 32;
}
二、HashMap中有hash (函数,再次计算了Objects的散列值
1 .计算方法
staticfinalinthash(objectkey ) {
int h; return(key==null )? 0:(h=key.hashcode () ) ) ) ) ) ) ) ) )。
}
重新计算的散列值是hashCode ) )计算的散列值与其自身向左移位了16位的数的异或
例如:
h=hashcode (-11110111111111111101101101110111011101
h16-00000000000011110111111
h ^ (h16 (-1111011111100101100001010=hash
2 .为什么这样计算
可以看到,哈希值是32位的二进制数字,如果将哈希值向右偏移16位,则正好为32位的一半。 也就是说,如果将自己的前16位和后16位进行异或,则在table数组的长度较小时,哈希值的高位也可以参与数组位置的计算
三.表阈值
在什么是HashMap这一节中,table的阈值并不一定是自己设定的容量负载因子,而是经过tableSizeFor () )函数的计算,由此可知该函数是什么
saticfinalinttablesizefor{
int n=cap - 1;
n |=n 1;
n |=n 2;
n |=n 4;
n |=n 8;
n |=n 16;
返回(n0 )? 1:(n=maximum_capacity? MAXIMUM_CAPACITY:n 1; }
首先,它的目的是找到最小的2的幂,它几乎等于用户给定的散列表的容量。 例如,如果用户给了7,我们就找到8,如果用户给了14,我们就需要找到16。 为什么能用这个方法找到呢? 让我看看
如果要找的数是最接近14的2的平方,那么很明显这个数是16,是2的4次方
16的二进制: 0001 0000
14的二进制数: 0000 1100
15的二进制: 0000 1111
请这样想。 我想用14计算16。 那么,你可以先计算15,然后再加1。 另一方面,15具有4个1的特征。 那么,现在的问题是14如何从其前0以外的数中将下一个数字全部转换为1。
首先14和15的第一位是0以外的数在同一位。 也就是说,不需要管理后面的数据,而只需要管理后面的数据。 用什么方法能把所有的数转换成1呢? 那是和1的进行和运算。
因此,考虑了可以将利14的第一位(或上位)的非零数和后面的数相加或运算。
Cap==14;
N=cap-1==13;
-1是为了防止如果用户提供的数本身是2的幂(如16 ),则在16-1之后仍可以//按以下方式计算期望的结果:
n |=n 1; 0000 1100
0000 0110
0000 1110
n |=n 2; 0000 1110
0000 0011
0000 1111
n |=n 4;
n |=n 8;
n |=n 16;
举个例子,在n进行了第一次或运算后,如果n的前两位变换为1,则可以使用前两位变换为3,4,位变换为1,所以在第二次和运算中n向右移动两位。 同样,在进行第二次运算后,n的前4位已经是1,可以用它们改变5、6、7、8位。 今后也一样。 所以,按照1、2、4、8、16的顺序向右移动。 那么,为什么向右移动16位后就停止了呢?
int在java中是4个子节的32比特,但是向右移动16比特的话,从上位的最初出现1的位置开始向右连续32比特变为1,已经超过了int的最大值,所以没有必要进行移位操作
方法最后把n 1变成了我们希望的2的乘方
四.根据哈希值计算数组中位置的方法
if () p=tab(I=(n-1 ) hash] ) )==null ) )
tab[I]=newnode(hash,key,value,null );
//n是数组的大小,是2的指数倍
这是putVal函数的短代码。 发现数组中的位置是用n-1和hash计算的
3.1为什么是n-1?
数组的长度n一定由2的指数倍(tableSizeFor ) )函数决定),所以n-1变换二进制时,下数位全部为1,前一位全部为0.00000000001111 ) 15 )
这样,在进行与散列值的乘积运算的情况下(在上述例子中) ) ) )。
0000 0000 0000 0000 0000 0000 0000 1111
1111 0101 1111 1111 0010 1110 0000 1010
0000 0000 0000 0000 0000 0000 0000 1010
进行与运算时,无论什么数和0与都为0,所以可以保证与运算的结果在0~n-1之间,即阵列下标的范围内,不会发生阵列越界
下一节:快速访问hashmap