JavaSE教程_进阶
package com.wkcto.hashmap;
import java.util.HashMap;
/**
* HashMap源码分析
* @author 北京极悦
*
*/
public class Test02 {
public static void main(String[] args) {
HashMap<String, Integer> hashMap = new HashMap<>();
/*
*1) 在无参构造方法中, 给HashMap的loadFactor字段赋值为0.75, 这是加载因子
* HashMap中定义了 Node<K,V> [] table数组, 默认初始化 null
*/
hashMap.put("lisi", 33);
/*
* 2) 在第一次执行put()方法添加<键,值>对时, 给table数组初始化, 默认初始化容量: 16
* 给threshold字段赋值 12 , 该字段的值 等于 默认的加载因子 * 数组默认的初始化容量
*/
/*
* 3) put()添加数据
* (1) 先根据键的哈希码(hashCode()方法的返回值)计算 键"lisi"的hash值: 3322017
* (2) 根据hash值,计算数组的下标, i = 1
* (3) 如果table[i] == null, 根据hash,key,value值创建一个结点保存到table[i]中
* 如果table[i] !=null, 遍历table[i]单向链表的每个结点, 如果有某个结点的key与当前的键equals()相等
* 就使用新的value值33替换原来的值; 如果所有结点的key都不相同,找到链表的尾部, 就根据当前键值对生成新的结点插入到链表的尾部
* 当单向链表中结点的数量 大于 8个时, 系统会把单向链表转换为红黑树,红黑树是由双向链表实现的
*/
int hash = hash("lisi");
System.out.println( hash );
int n = 16; //table数组默认的初始化容量
int i = (n - 1) & hash; //计算数组的下标
System.out.println( i ); //1
Integer v = hashMap.get("lisi");
/*
* 4) get()返回键对应的值
* (1) 根据键的hashCode()计算hash值
* (2) 如果table == null, 或者table.length > 0 不成立, 或者 table[i]元素为null, 直接返回null
* (3) 遍历table[i]单向链表上每个结点, 如果有某个结点的键与当前的键equals()相等, 就返回该结点的value值, 如果没有匹配的结点返回null
*/
/*
* 5) HashMap在定义时, 可以指定一个初始化容量, 需要指定为2的幂次方,如果不是2的幂次方,系统会自动调整为2的幂次方
* 假设初始化容量为33~63之间的数,系统会调整为64, 为什么? 就是为了能够快速的得出数组的下标
* 数组的下标计算公式: (n - 1) & hash , 把hash值与n-1进行按位与操作
* 当n==64时, n-1的值是63,它的二进制为 0011 1111 , 在与hash值进行按 位与操作时, 就是把hash值的最后6位作为数组的下标
*/
HashMap<String, String> hashMap2 = new HashMap<>(33);
hashMap2.put("aa", "bbb");
}
//根据键key计算它的hash值,
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
}