Java面向对象
Java异常
Java数组
Java常用类
Java集合
Java IO流
Java线程
Java反射
Socket编程
Java注解开发
Java GoF设计模式
HashMap
Java内存模型
Java线性表

Java HashMap源码分析

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);
    }
}