1.hashMap的关键值
DEFAULT_INITIAL_CAPACITY:默认初始容量16,∈(0,1<<30),实际大小为2的整数次幂;
DEFAULT_LOAD_FACTOR
:默认加载因子0.75,
threshold
:阈值,resize的判断条件。(threshold=容量*加载因子)
2.hashMap 的构造函数
public HashMap(int initialCapacity, float loadFactor) {//传入指定容量、加载因子
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
threshold = initialCapacity;
init();
}
public HashMap(int initialCapacity) { //指定容量,加载因子0.75
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
public HashMap() { //默认容量16,加载因子0.75
this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
}
public HashMap(Map<? extends K, ? extends V> m) {//构造一个映射关系与指定 Map 相同的新 HashMap.(一直不明白这样构造和new HashMap(); 然后 map.putAll(map2) 有什么区别?希望看到的大神讲解一下··)
this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
inflateTable(threshold);
putAllForCreate(m);
}
3.hashMap的get()、put()方法
①put
public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); } if (key == null) //如果key为null① return putForNullKey(value); int hash = hash(key); int i = indexFor(hash, table.length); //key不为null,根据key的hash值计算出table位置 (i = hash & 容量 ) for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { //遍历对比key==this.key?新值替换旧值,返回旧值:新增entry V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i);//② return null; //返回值不为null,说明这次put发生了新旧值得替换 }
private V putForNullKey(V value) { //put进去key为null的键值对 ①
for (Entry<K,V> e = table[0]; e != null; e = e.next) { //key为null的entry默认放在table[0],遍历table[0]的entry
if (e.key == null) { //若果以前有key为null的entry
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue; //新值替换旧值,并且返回旧值
}
}
modCount++;
addEntry(0, null, value, 0); //以前没有当前key值,新增entry,②
return null;
}
void addEntry(int hash, K key, V value, int bucketIndex) {//新增entry②
if ((size >= threshold) && (null != table[bucketIndex])) { //size(key-value对)达到阈值 && 当前table不是空的---》resize④
resize(2 * table.length); //扩容为当前2倍,根据新的容量重新计算分配map中entry的位置
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);
}
createEntry(hash, key, value, bucketIndex); //新建entry ③
}
void createEntry(int hash, K key, V value, int bucketIndex) { //新建entry ③
Entry<K,V> e = table[bucketIndex]; //那到当前table的第一个entry(马上第一要变第二了!)
table[bucketIndex] = new Entry<>(hash, key, value, e); //把新entry插入到table的第一格
size++; //key-value对数量加一
}
②get
public V get(Object key) { if (key == null) return getForNullKey(); //返回key为null的value ① Entry<K,V> entry = getEntry(key); //拿到key的entry ② return null == entry ? null : entry.getValue(); //返回entry的value }
private V getForNullKey() { //如果map.get(null) 返回table[0]中key为null的value,没有返回null ①
if (size == 0) { //hashMap已占用槽的长度
return null;
}
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null)
return e.value;
}
return null;
}
final Entry<K,V> getEntry(Object key) { ②
if (size == 0) { //判断map中的key-value对不是0
return null;
}
int hash = (key == null) ? 0 : hash(key); //获取key的hash值
for (Entry<K,V> e = table[indexFor(hash, table.length)]; //通过hash值和容量计算出table位置n,遍历table[n]里面的entry对比key相等的返回entry
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
③remove
public V remove(Object key) { Entry<K,V> e = removeEntryForKey(key); return (e == null ? null : e.value); //remove方法返回删除掉的value }
final Entry<K,V> removeEntryForKey(Object key) {
if (size == 0) {
return null;
}
int hash = (key == null) ? 0 : hash(key);
int i = indexFor(hash, table.length); //通过hash计算index
Entry<K,V> prev = table[i]; //首次遍历是未 table[i] 的头entry
Entry<K,V> e = prev; //用于遍历的entry
while (e != null) {
Entry<K,V> next = e.next; //拿到后项entry
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) { //找到要删除的key的entry
modCount++;
size--; //删除后size减一
if (prev == e) //如果要删除的是 table[i]的头entry
table[i] = next; //老二晋升为 table[i]的头entry
else
prev.next = next; //前一entry的next指向后一entry(删除当前entry)
e.recordRemoval(this);
return e;
}
prev = e; //将当前entry设为前女友
e = next; //下一个
}
return e;
}
④clear
public void clear() { modCount++; //对map的操作次数,用于迭代时的线程安全 Arrays.fill(table, null); size = 0; //数组中的entry数量设为0,此时的容量没有缩小。仍为clear前的容量 } public static void fill(Object[] a, Object val) { for (int i = 0, len = a.length; i < len; i++) //遍历将数组的所有值设为null, a[i] = val; }
⑤containsValue
public boolean containsValue(Object value) { if (value == null) return containsNullValue(); Entry[] tab = table; for (int i = 0; i < tab.length ; i++) //遍历数组 for (Entry e = tab[i] ; e != null ; e = e.next) //遍历entry if (value.equals(e.value)) return true; return false; } private boolean containsNullValue() { Entry[] tab = table; for (int i = 0; i < tab.length ; i++) for (Entry e = tab[i] ; e != null ; e = e.next) if (e.value == null) return true; return false; }