源码分析 - JDK 1.7
//1. HashMap 的 K,V的值,在创建对象的时候确定,比如:K:Integer V: String
public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
{
//重要属性:定义了一个16,赋给初始化数组长度
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
//定义了一个很大很大的数
static final int MAXIMUM_CAPACITY = 1 << 30;
//定义了加载因子,为 0.75
static final float DEFAULT_LOAD_FACTOR = 0.75f;
//定义空的主数组
static final Entry<?,?>[] EMPTY_TABLE = {};
//添加的元素的数量
transient int size;
//定义个变量,没赋值,为0 。 --- 这个变量用来表示数组扩容的边界值,
int threshold;
//加载因子,这个变量用来接收 加载因子的值
final float loadFactor;
}
构造器
//空构造器
public HashMap() {
//this.(16,0.75)
this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
}
//有参的构造器, 16, 0.75 ---------》 不建议使用者调用这个构造器
public HashMap(int initialCapacity, float loadFactor) {
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
//确定了加载因子,0.75
this.loadFactor = loadFactor;
//扩展数组的边界值
threshold = initialCapacity;
init();
}
PUT方法
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
if (key == null) // 对空值进行判断,允许key的值为空
return putForNullKey(value);
int hash = hash(key); // 获取hash码
int i = indexFor(hash, table.length);//得到元素在数组中的位置
// 通过放入的数组上,没有元素的话,那么直接添加元素,不走这个for循环。
//如果e!= null 满足,就证明这个位置上有元素,
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
//发生哈希碰撞的时候,会先比较哈希值,
// 比较key是否是一个对象,如果是,equals就不比较了
// 比较key是否是一个对象,如果不是,则比较equals
// 如果hash值一样,equals方法比较的结果也一样,那么才会走这个方法
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;// 新value 替换 老 value, 只替换value,不替换value
e.recordAccess(this);
return oldValue;// 将old 的value返回,即原始的value值
}
}
addEntry(hash, key, value, i);
return null;
}
// 获取Key 的 hashcode 的方法
final int hash(Object k) {
int h = hashSeed;
if (0 != h && k instanceof String) {
return sun.misc.Hashing.stringHash32((String) k);
}
//进行了二次散列,没有直接用hashcode的值性,减少冲突
h ^= k.hashCode();
//扰动函数,核心思想:增加hashcode的不确定
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
static int indexFor(int h, int length) {
// 计算位置对应的公示,等效于 h % length取余数,因为这样效率高
return h & (length-1);
}
//添加元素的方法
void addEntry(int hash, K key, V value, int bucketIndex) {
//如果这个size 》= threshold ,这个if不走了
if ((size >= threshold) && (null != table[bucketIndex])) {
resize(2 * table.length);
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);
}
//创建一个Entry对象
createEntry(hash, key, value, bucketIndex);
}
//创建一个Entry对象
void createEntry(int hash, K key, V value, int bucketIndex) {
//将下标位置上的元素给e
Entry<K,V> e = table[bucketIndex];
//封装对象,将这个对象给table[bucketIndex] -----------》 链表的《头插法》
table[bucketIndex] = new Entry<>(hash, key, value, e);
//元素数量+1
size++;
}
扩容resize
//添加元素的方法
void addEntry(int hash, K key, V value, int bucketIndex) {
//如果这个size 》= threshold ,这个if不走了
if ((size >= threshold) && (null != table[bucketIndex])) { // 如果size 大于 12(16*0.75) 并且 该位置有元素了,才会去扩容
resize(2 * table.length); // 扩容大为2倍
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);
}
//创建一个Entry对象
createEntry(hash, key, value, bucketIndex);
}
void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
Entry[] newTable = new Entry[newCapacity];
transfer(newTable, initHashSeedAsNeeded(newCapacity)); // transfer 将新数组给老数组
table = newTable;
threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
}