Hashmap1.7 构造器
public HashMap(int initialCapacity, float loadFactor) {
//initialCapacity初始值 默认16 loadFactor加载因子 默认0.75
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
//如果初始值设为最大,则取HashMap的最大存储量 2的16次方
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
//如果超过这个数,HashMap则扩容
threshold = initialCapacity;
init();
}
HashMap 的put方法
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
//下面有介绍 ,看1-1代码,简单来说这里初始化HashMap的数组
inflateTable(threshold);
}
//如果键为null,则放入entry【0】
if (key == null)
return putForNullKey(value);
//得到hash值
int hash = hash(key);
//得到该元素存入的数组下标
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
//如果该元素跟存储的元素的hash值跟key值相等,则替换value值,返回旧值
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
//已经存储的元素个数加1 主要用于快速失败机制
modCount++;
//上面的循环已经发现没有相同值了,执行插入语句,该方法有介绍
addEntry(hash, key, value, i);
return null;
}
1-1代码 inflateTable方法
private void inflateTable(int toSize) {
// Find a power of 2 >= toSize
//找出大于tosize但最小的2的n次方数,比如14的就是16,17的就是32
int capacity = roundUpToPowerOf2(toSize);
//重新赋值给扩容数
threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
//建立一个新的entry,长度为capacity
table = new Entry[capacity];
//看1-2代码
initHashSeedAsNeeded(capacity);
}
1-2代码 initHashSeedAsNeeded(capacity);
final boolean initHashSeedAsNeeded(int capacity) {
//hashSeend的值为0,而且只有这个方法才能改变 为false
boolean currentAltHashing = hashSeed != 0;
//这是获取JVM变量,这可以进行设置,一般为true
boolean useAltHashing = sun.misc.VM.isBooted() &&
(capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
boolean switching = currentAltHashing ^ useAltHashing;
if (switching) {
hashSeed = useAltHashing
? sun.misc.Hashing.randomHashSeed(this)
: 0;
}
//返回true
return switching;
}
void addEntry(int hash, K key, V value, int bucketIndex) {
//存储的元素大于扩容值,而且该数组下标没有存储元素,而进行扩容
if ((size >= threshold) && (null != table[bucketIndex])) {
//扩容方法,有介绍
resize(2 * table.length);
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);
}
//插入函数
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
Entry[] newTable = new Entry[newCapacity];
//将旧数组的所有元素转移到新的数组中,有方法介绍
transfer(newTable, initHashSeedAsNeeded(newCapacity));
//给该对象的table
table = newTable;
//重新计算扩容值
threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
}
void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;
for (Entry<K,V> e : table) {
while(null != e) {
//只要元素还没到最后一个都不是为null
Entry<K,V> next = e.next;
//rehash 是判断是否要重新计算hash值,这个变量在initHashSeedAsNeeded方法中已经说明了,一般为false
if (rehash) {
e.hash = null == e.key ? 0 : hash(e.key);
}
//通过之前计算发hash值(之前刚进行put方法时就计算了,存储在每个元素中)
int i = indexFor(e.hash, newCapacity);
//下三行表示用头插法把元素插入数组中
e.next = newTable[i];
newTable[i] = e;
e = next;
}
}
}