hashMap总结
hashMap结构
hashMap结构如图 一般是由数组和链表组成 红黑树暂时忽略 比较难 也没什么必要
数组:
transient Node<K, V>[] table;
链表:
static class Node<K, V> implements Map.Entry<K, V> {
final int hash;
final K key;
V value;
Node<K, V> next;
Node(int hash, K key, V value, Node<K, V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
数组我们很好理解,而这里的链表我的好好说说,从上面的结构可以看到 Node<K, V> next; 其实就是下一个节点,简单来说就是套娃,举个例子 就是A包含B ,B包含C 依次下去,其实数组每个位置其实只是放了一个node节点对象,只是我们不停的获取node节点对象中next属性从而获取下一个node节点的值从而构成了我们所说的链表
注意:我们本文将数组中位置称为bucket. 比如说数组1号位置 我们称为1号bucket
重点:
(1)负载因子:
final float loadFactor; //键值对数量/数组长度 = loadFactor 不能超过这个值,否则就要扩容
(2)键值对最大数量
int threshold; //键值对最大数量 = 数组长度*loadFactor
put 源码分析
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
//hashMap的hash算法
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
当我们使用put方法的时候,底层实际上去调用的putVal的方法,这边我们需要注意点是hashMap使用自己的hash算法.
(1) hash()算法
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
hashMap的hash算法是根据key来进行计算的,我们这边需要把这个算法进行拆分为3个部分,【1】h = key.hashCode(),【2】h >>> 16,【3】^
【1】h = key.hashCode()
这个就是跟key本身的hash算法有关的,hash值是32位的 0000 0000 0000 0000 0000 0001 0000 0000,一般我们我们是String,HashMap 内部实现是通过 key 的 hashcode 来确定 value 的存储位置,因为字符串是不可变的,所以当创建字符串时,它的 hashcode 被缓存下来,不需要再次计算,所以相比于其他对象更快。
【2】h >>> 16
这个是将计算后的hash值无符号右移16位.比如说 h = 0000 0000 0000 0001 0000 0001 0000 0000 右移16位后得到 0000 0000 0000 0000 0000 0000 0000 0001
【3】^
这个是进行异或的位运算 之所以进行位运算 就是让这些存放的更加均匀 0000 0000 0000 0001 0000 0001 0000 0000 ^ 0000 0000 0000 0000 0000 0000 0000 0001 = 0000 0000 0000 0001 0000 0001 0000 0001
注意点:为什么更加均匀了 ???
解答: 因为1出现的次数可能会增加了.这跟他确定键值对存储到数组哪个位置有关系。
tab[i =