前言:
HashMap的包结构
*注意,此实现不是同步的。
好吧“哈希表”是啥,内部结构是什么样的?
哈希表:
什么是哈希表?
HashMap是怎么实现散列函数和处理冲突的?
public static void main(String[] args) {
HashMap<String, String> blogMap=new HashMap<>();
blogMap.put("博文测试", "博文测试Value");
blogMap.get("博文测试");//此行打断点
}
观察Variables,如下图
拉链法的简单介绍:
HashMap 拉链法的实现分析
HashMap中的m(散列表长度)和a(装载因子)
/**
* The load factor used when none specified in constructor.
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;默认散列表长度:
/**
* The default initial capacity - MUST be a power of two.
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
HashMap中的PUT方法
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);//我们看到在方法内部对key做了一次hash运算,然后调用putVal方法,我们暂且不关心后两个参数在干嘛,回头解释
}
static final int hash(Object key) {//先判断key是否为null,如果为null,hash值为0,否则以hashCode方法值为准
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
2、由于Object的hashCode返回的是对象的hash值,所以即使equals返回TRUE,集合也可能判定两个对象不等,所以必须重写hashCode方法,以保证当equals返回TRUE时,hashCode也返回Ture,这样才能使得集合中存放的对象唯一。
/**
* Implements Map.put and related methods
*
* @param hash hash for key
* @param key the key
* @param value the value to put
* @param onlyIfAbsent if true, don't change existing value
* @param evict if false, the table is in creation mode.
* @return previous value, or null if none
*/
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0) //这一行的意思是如果table(主存储结构)没有初始话,则初始化一个数组并赋值给tab,初始化代码在resize方法中
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null) //根据散列值算出数组索引((n - 1) & hash)并判断该索引下是否有值,如果没有则新建一个首节点
tab[i] = newNode(hash, key, value, null);
else {//位置下有值
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))//如果该节点的key一致,那么e=p
e = p;
else if (p instanceof TreeNode) //当为红黑树时相关处理
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) { //如果p的next指针为null
p.next = newNode(hash, key, value, null); //为p后面添加一个节点
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st //如果链表过长时,转换成红黑树。这个值表示当某个箱子中,链表长度大于 8 时,有可能会转化成树。
treeifyBin(tab, hash);//转换方法
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value; // 新值替换旧值,并返回旧值
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold) //map里的元素个数(size)大于一个阈值(threshold)时,map将自动扩容
resize();
afterNodeInsertion(evict);
return null;
}
当不同的对象hashCode发生碰撞时,HashMap通过单链表来解决,将新元素加入链表表头,通过next指向原有的元素。单链表在Java中的实现就是对象的引用(复合)。
7万+



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



