0%

JKD1.8 hashmap源码分析

“道可道,非常道;名可名,非常名。
无名,万物之始,有名,万物之母。
故常无欲,以观其妙,常有欲,以观其徼。
此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。” ^1

Nosql的鼻祖往前追朔在Java这一支是要落到HashMap的头上的。关于HashMap,jdk1.8和之前的版本相比有较大的改动。在JDK1.8之前,HashMap采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,HashMap采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。

先来看一下 HashMap 的继承图:
类继承图

HashMap 根据键的 hashCode 值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。 HashMap 最多只允许一条记录的键为 null ,允许多条记录的值为 null 。HashMap 非线程安全,即任一时刻可以有多个线程同时写 HashMap,可能会导致数据的不一致。如果需要满足线程安全,可以用 Collections的synchronizedMap 方法使 HashMap 具有线程安全的能力,或者使用ConcurrentHashMap 。
#####HashMap 存储结构
HashMap是数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的,链表和红黑树都是为了优化hash值冲突而实行的优化方案,当链表的长度大于8时链表将转换成红黑树,如下图所示:
存储结构

#####HashMap 各常量、成员变量作用  

1
/**
2
     * The table, initialized on first use, and resized as
3
     * necessary. When allocated, length is always a power of two.
4
     * (We also tolerate length zero in some operations to allow
5
     * bootstrapping mechanics that are currently not needed.)
6
     * table就是存储Node类的数组
7
*/  
8
transient Node<K,V>[] table;  
9
10
/**
11
  * The number of key-value mappings contained in this map.
12
  *  记录hashmap中存储键-值对的数量
13
  */  
14
transient int size;  
15
16
/**
17
  * hashmap结构被改变的次数,fail-fast机制
18
  */  
19
transient int modCount;  
20
21
    /**
22
     * The next size value at which to resize (capacity * load factor).
23
     * 扩容的门限值,当size大于这个值时,table数组进行扩容
24
     */  
25
    int threshold;  
26
27
    /**
28
     * The load factor for the hash table.
29
     *
30
     */  
31
 float loadFactor;  
32
/**
33
     * The default initial capacity - MUST be a power of two.
34
     * 默认初始化数组大小为16
35
     */  
36
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16  
37
38
    /**
39
     * The maximum capacity, used if a higher value is implicitly specified
40
     * by either of the constructors with arguments.
41
     * MUST be a power of two <= 1<<30.
42
     */  
43
    static final int MAXIMUM_CAPACITY = 1 << 30;  
44
45
    /**
46
     * The load factor used when none specified in constructor.
47
     * 默认装载因子,
48
     */  
49
    static final float DEFAULT_LOAD_FACTOR = 0.75f;  
50
51
    /**
52
     * The bin count threshold for using a tree rather than list for a
53
     * bin.  Bins are converted to trees when adding an element to a
54
     * bin with at least this many nodes. The value must be greater
55
     * than 2 and should be at least 8 to mesh with assumptions in
56
     * tree removal about conversion back to plain bins upon
57
     * shrinkage.
58
     * 这是链表的最大长度,当大于这个长度时,链表转化为红黑树
59
     */  
60
    static final int TREEIFY_THRESHOLD = 8;  
61
62
    /**
63
     * The bin count threshold for untreeifying a (split) bin during a
64
     * resize operation. Should be less than TREEIFY_THRESHOLD, and at
65
     * most 6 to mesh with shrinkage detection under removal.
66
     */  
67
    static final int UNTREEIFY_THRESHOLD = 6;  
68
69
    /**
70
     * The smallest table capacity for which bins may be treeified.
71
     * (Otherwise the table is resized if too many nodes in a bin.)
72
     * Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts
73
     * between resizing and treeification thresholds.
74
     */  
75
    static final int MIN_TREEIFY_CAPACITY = 64;