HashMap实现原理和源码分析

235 阅读3分钟

数据结构

最核心的其实就是数据结构,那具体是什么呢?

三大核心数据结构:数组 + 链表 + 红黑树。


看架构图

1.上面一行是数组
这种情况是key的hash取模的值不重复。

2.竖着的两列是模值重复的情况
1)即有可能是链表
链表的数据数量大于8,就会自动转换为红黑树。
2)也有可能是红黑树

数组

先看数组,数组的作用是,key的hash进行取模,这个模的值就是数组索引,key/value这个Node就存储到这个索引的位置。

如果取模的值一样怎么办?不一样的key,取模可能得到不一样的值,那怎么存储呢?

这个时候,就得用链表,详细见下文。


Node类

存储了key/value,看源码:java.util.HashMap.Node

static class Node<K,V> implements Map.Entry<K,V> {
        final int hash; //key的hash
        
        final K key; //存储了key/value
        V value;
        
        Node<K,V> next;

这里再注意一下几个数据:

1、  key

2、  key的hash

3、  hash取模
这个对应数组索引

4、  key/value到底存储在哪里?
key/value本身是存储在Node节点。
但是怎么把这些Node节点,即不同的key/value给组装起来呢?这个时候,就需要数据结构。什么数据结构?数组。所以,Node类存储了key/vaue的值,数组这个数据结构把不同的key/value给关联起来。一个是存储值,一个是存储关系。

链表

刚才说到,模值一样,就要用到链表。所以,链表要解决的问题,就是模值一样的key,到底怎么存储。

其实就是用链表,说白了,就是往链表后面插数据即可。

写的时候,是往后面插。那读的时候,怎么读呢?既然模值都一样,那怎么知道哪个key对应哪个value呢?

其实是可以的,别慌,其实就是两步:

1、  先找到模值,即数组的索引

2、  如果索引一样,继续找到key值
注意这里,key值是不一样的。我们前面说的是,不同的key,模值一样,但是请注意,模值一样,key不一样。所以,我们比较的时候,就是先比较模值,如果模值一样,再比较key值,这样就可以找到那个key对应的value。

核心点:找模值/索引的时候,是在数组里找。找key值的时候,是在链表里找。

到目前为止,好像问题都解决了,即模值不一样,就存储在数组,模值一样,就存储到链表。那为什么还需要红黑树呢?

知识点来了,链表是为了解决模值重复/冲突的问题,而红黑树是为了解决高性能的问题。

怎么说?链表的读速度很慢,即遍历速度很慢,因为是顺序遍历。所以,如果链表的数据很多的话,那么读速度就很慢,说白了,就是map的查找数据很慢,那怎么解决呢?红黑树。

树要解决的问题,就是综合了数组和链表的优点,即读速度很快,写速度也很快。

最后总结一下,具体来说,就是链表的数据如果超过8,那么就自动转换为树;如果树的数据后面因为删除又变少了,那么又会自动转换为链表。反正就是可以互相转换。

最后再注意一下,节点和树节点有点不一样,使用的是不同的类。

参考

java高并发和集合框架