[Java] HashMap 源码简要分析
特性
* 允许null作为key/value。
* 不保证按照插入的顺序输出。使用hash构造的映射一般来讲是无序的。
* 非线程安全。
* 内部原理与Hashtable类似。
源码简要分析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
public
class
HashMap<K,V>
{
static
final
int
DEFAULT_INITIAL_CAPACITY =
16
;
// 默认初始容量是16。(必须是2的次方)
static
final
int
MAXIMUM_CAPACITY =
1
<<
30
;
// 即2的30次方
static
final
float
DEFAULT_LOAD_FACTOR =
0
.75f;
// 默认装载因子
Entry[] table;
// Entry表
int
size;
// Entry[]实际存储的Entry个数
int
threshold;
// reash的阈值,=capacity * load factor
final
float
loadFactor;
// 构造函数
public
HashMap(
int
initialCapacity,
float
loadFactor) {
// 找到一个比initialCapacity大的最小的2的次方数
int
capacity =
1
;
while
(capacity < initialCapacity)
capacity <<=
1
;
}
this
.loadFactor = loadFactor;
threshold = (
int
)(capacity * loadFactor);
table =
new
Entry[capacity];
// addEntry()
void
addEntry(
int
hash, K key, V value,
int
bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] =
new
Entry<>(hash, key, value, e);
if
(size++ >= threshold)
resize(
2
* table.length);
}
// put():添加元素
public
V put(K key, V value) {
int
hash = hash(key.hashCode());
// key的hash值
int
i = indexFor(hash,table.length);
// 槽位
// 寻找是否已经有key存在,如果已经存在,使用新值覆盖旧值,返回旧值
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))) {
V oldValue = e.value;
e.value = value;
return
oldValue;
}
}
// 添加Entry
addEntry(hash,key,value,i);
return
null
;
}
// resize():重新哈希
void
resize(
int
newCapacity) {
Entry[] oldTable = table;
int
oldCapacity = oldTable.length;
Entry[] newTable =
new
Entry[newCapacity];
transfer(newTable);
table = newTable;
threshold = (
int
)(newCapacity * loadFactor);
}
/**
* Transfers all entries from current table to newTable.
*/
void
transfer(Entry[] newTable) {
Entry[] src = table;
int
newCapacity = newTable.length;
for
(
int
j =
0
; j < src.length; j++) {
Entry<K,V> e = src[j];
if
(e !=
null
) {
src[j] =
null
;
do
{
Entry<K,V> next = e.next;
int
i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
}
while
(e !=
null
);
}
}
}
}
|
遍历方式
* 低效遍历:按照Key进行遍历,则每次都需要按Key查找槽位(不同的Key有重复查找),且可能需要遍历槽位上所在Entry链表(不同的Key有重复遍历)。
* 高效遍历:HashMap的entrySet()返回自定义的EntryIterator,是先按照槽位遍历一次,再遍历一次槽位上Entry链表。
1
2
3
4
5
6
|
Map<String, String[]> paraMap =
new
HashMap<String, String[]>();
for
( Map.Entry<String, String[]> entry : paraMap.entrySet() )
{
String appFieldDefId = entry.getKey();
String[] values = entry.getValue();
}
|