JDK1.8 HashMap详解
一、基础补充
- hash冲突解决的方式(面试中可能会问)
- 开放定址法:查询产生冲突的地址的下一个地址是否被占用,知道寻找到空的地址为止;
- 再散列法:利用散列函数对上一步的hash值再进行散列;
- 连地址法:对于hash值相等的,通过链表链接起来,HashMap中采用了该方式
二、源码分析
HashMap的结构
首先,hashMap的主干是一个Node数组(jdk1.7及之前为Entry数组)每一个Node包含一个key与value的键值对,与一个next,next指向下一个node,hashMap由多个Node对象组成。
Node是HhaspMap中的一个静态内部类 :
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
// 这里的hashCode使用key和value的hashcode值的异或实现
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
- 补充解释说明:
- Node是一个内部类,继承了Map.Entry
- Node的hashCode方法使用key和value的hashcode值异或运算产生
HashMap的几个重要字段
//默认初始容量为16,0000 0001 右移4位 0001 0000为16,主干数组的初始容量为16,而且这个数组
//必须是2的倍数(后面说为什么是2的倍数)
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
//最大容量为int的最大值除2
static final int MAXIMUM_CAPACITY = 1 << 30;
//默认加载因子为0.75
static final float DEFAULT_LOAD_FACTOR = 0.75f;
//阈值,如果主干数组上的链表的长度大于8,链表转化为红黑树
static final int TREEIFY_THRESHOLD = 8;
//hash表扩容后,如果发现某一个红黑树的长度小于6,则会重新退化为链表
static final int UNTREEIFY_THRESHOLD = 6;
//当hashmap容量大于64时,链表才能转成红黑树
static final int MIN_TREEIFY_CAPACITY = 64;
//临界值=主干数组容量*负载因子
int threshold;
- 补充解释
- 链表树化的临界值是8, 退化为链表的临界值是6,是为了防止链表长度若在7和8来回变化,会引起红黑树的频繁建立和退化,效率更低
构造方法
//initialCapacity为初始容量,loadFactor为负载因子
public HashMap(int initialCapacity, float loadFactor) {
//初始容量小于0,抛出非法数据异常
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
//初始容量最大为MAXIMUM_CAPACITY
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
//负载因子必须大于0,并且是合法数字
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
//将初始容量转成2次幂
this.threshold = tableSizeFor(initialCapacity);
}
//tableSizeFor的作用就是,如果传入A,当A大于0,小于定义的最大容量时,
// 如果A是2次幂则返回A,

本文详细讲解了JDK1.8 HashMap的基础知识和源码分析,包括HashMap的结构、重要字段、构造方法、put和get过程,以及resize()方法的工作原理。通过深入理解HashMap的实现,有助于提升对Java集合框架的理解。
最低0.47元/天 解锁文章
171

被折叠的 条评论
为什么被折叠?



