hashmap方法
tableSizeFor:获取最小2整数幂
作用是查找大于等于传参容量的最小2的整数幂,赋值给threshold阈值。由于扩容是当前数组下标值加上原数组长度,所以需要扩充到原先两倍大小,又因为初始是16,所以一定扩容后的大小是2的整数幂。
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
作用就是获取一个满足大于等于cap(传入参数,原容量)且是2的整数幂的数之中最小的数。
首先-1是当cap本身就是2的整数幂的时候,满足包含自身,也就是扩容后的结果还是cap。
|= : n=n| (n >>> 1)
|:左右两个元素位运算,都是0时该位才是0
n>>> 1: n的二进制向右移动1位,左边高位空出来的补0
代码目的就是把n的非0最高位的后面全变成1(0000100变成了0000111)
这样在+1就获得了最小的2的整数幂并且大于等于n
hash:判断hash值(只考虑key)
- ^是异或方法 : 左右值相同是0,不同是1
- 1.8 中用的是key的hashcode,注意这里和高16位做了一个异或,可以防止hash数组太小时,hash值的高位被忽略,也就是太小左
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
- 桶定位: 用的方法是hash & (table.length -1),也就是hash方法得到的hash值和table数组的长度-1,取并。(相当于h%length)
hashcode, ==, equals, compareTo()区别
== 比较的是变量的句柄存储地址,而不是实际存储内容
equals比较的是实际的存储内容,所以自定义类需要重写equals方法,否则继承Object中的equals方法,还是比较句柄地址和==一样。(因为Object类中的equals只是判断两个引用变量是否引用同一对象,如果不是引用同一对象,即使两个对象的内容完全相同,也会返回false。)
hashcode:hashcode是将物理地址转换成一个int数进行比较,同一地址才相同。
和equals方法没有强制关系,也需要重写。保证结果是hashcode相同equals不一定相同,equals为真两对象相等hashcode一定相等。
compareTo(): 获取的字符串(也可以是其他对象)的长度,然后作减法,这里的减法就是ASCII码的减法,所以compareTo()会返回数字,如果两个字符串内容相同,会返回0,字符串a大于字符串b,会返回相差的ASCII码的正数,字符串a小于字符串b,会返回相差的ASCII码的负数。
简而言之就是从长度不同返回长度差,长度相同返回编码差值。
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
hashmap中equals返回true那么compareTo函数应该也返回0?
resize:扩容
作用:初始化和扩容table数组,返回的是Node数组
主要思路:
-
先存储旧(未扩容)数组的长度、阈值等
-
如果旧数组长度大于0
如果旧数组长度超过或者等于最大容量限制,不能继续扩容,只能把阈值赋值为最大整型,返回旧数组。
如果扩容后仍然不超过最大容量限制,就扩容一倍,阈值也翻一倍。
-
如果旧数组 为null或者长度等于0
阈值大于0,阈值就是新数组的大小
阈值也等于0,就用默认参数来构造新数组
-
新阈值计算
-
根据新阈值和新容量来new一个新的桶数组。
-
把旧桶数