一、HashMap底层数据结构
JDK7之前,HashMap 底层是 hash 数组和单向链表实现。
![](https://i-blog.csdnimg.cn/blog_migrate/abfd1c2b6c2636001de21bf0cb9f061c.png)
JDK8后采用数组+链表+红黑树的数据结构。
二、HashMap 的工作原理
在创建HashMap对象时,可以初始化默认容量和负载因子,当然也可以在创建HashMap对象时指定初始容量和负载因子(这取决于创建HashMap对象时调用的构造函数)。
通过put()方法存储数据,当使用put()方法将键和值传递给HashMap时,首先会使用key的hashCode()方法获取key的hash值,然后通过公式:hash值 =(通过hashCode()得到的哈希值)^(异或)(哈希值右移16位),得到int类型的hash值,此hash值可以在存储时计算数据在hash桶数组中的下标位置,hash桶是node类型的数组,存储的都是node对象,而node本质上是Map.Entry(主要方便转化为红黑树),key和value都是先存储到node中,然后把node在存储到hash桶数组中,而node存储在hash桶数组中的下标位置是通过key的hash值计算出来的。
通过get(key)方法获取存储在HashMap中的数据,首先会通过key的hashCode()方法获取到key的hash值,首先会使用key的hashCode()方法获取key的hash值,然后通过公式:hash值 =(通过hashCode()得到的哈希值) ^(异或)(哈希值右移16位),得到int类型的hash值,此hash值可以在获取数据时,计算出数据在hash桶数组中的下标位置。之后调用HashMap的getNode()方法,在此方法中会判断当前的hash桶数组是否存有数据(判断是否null,判断长度是否为0,通过计算下标位置获取数据是否为null),如果没存有数据,则返回null,如果存有数据,则需要判断之前取得的int类的hash值和获取数据的hash值以及传递过来的key和获取数据的key地址及内容是否一致,一致,返回获取的数据,然后再获取value的值,返回给调用方;不一致, 则判断获取的数据是否是红黑树,如果是红黑树则从根节点开始进行匹配如果有对应的数据则返回,然后再获取value的值,返回给调用方,否则返回Null;如果是链表的话就会循环查询链表,如果当前的节点不匹配的话就会从当前节点获取下一个节点来进行循环匹配,如果有对应的数据则返回,然后再获取value的值,返回给调用方,否则返回Null。
三、使用HashMap时,当两个对象的 hashCode 相同怎么办?
因为HashCode 相同,equals()方法操作可能相等,也可能不相等,所hashCode值相同并不能说明是同一个对象,只有两个对象所在数组的下标相同,"碰撞"才会发生。如果振的hash值冲突了, HashMap会把产生hash冲突的hash值以链表形式存储在index位置上。
四、HashMap 的哈希函数怎么设计的?
HashMap的hash()函数源码如下:
![](https://i-blog.csdnimg.cn/blog_migrate/9a456b04596b7ba0bbd565d2e9801e92.png)
hash 函数是先拿到通过 key 的 hashCode ,是 32 位的 int 值,然后让hashCode 的高 16 位和低 16 位进行异或操作。两个好处:一定要尽可能降低 hash 碰撞,越分散越好; 算法一定要尽可能高效,因为这是高频操作, 因此采用位运算;
五、HashMap遍历方法有几种?
Iterator 迭代器
1
public class
MapDemo1
{
2
3
public static void
main
(
String
[]
args
) {
4
HashMap
<
String
,
String
>
map
=
new
HashMap
<>
();
5
map
.
put
(
"name1"
,
"
张三
"
);
6
map
.
put
(
"name1"
,
"
张三
"
);
7
map
.
put
(
"name2"
,
"
李四
"
);
8
map
.
put
(
"name3"
,
"
王五
"
);
9
map
.
put
(
"name4"
,
"
赵六
"
);
10
11
Iterator
<
Map
.
Entry
<
String
,
String
>>
iterator
=
map
.
entrySet
().
iterator
();
12
while
(
iterator
.
hasNext
()){
13
Map
.
Entry
<
String
,
String
>
entry
=
iterator
.
next
();
14
String key
=
entry
.
getKey
();
15
String value
=
entry
.
getValue
();
16
//String value1 = map.get(key);
17
System
.
out
.
println
(
key
+
"‐‐‐‐‐"
+
value
);
18
}
19
}
20
}
最常见的使用方式,可同时得到 key、value 值
1
public class
MapDemo1
{
2
3
public static void
main
(
String
[]
args
) {
4
HashMap
<
String
,
String
>
map
=
new
HashMap
<>
();
5
map
.
put
(
"name1"
,
"
张三
"
);
6
map
.
put
(
"name1"
,
"
张三
"
);
7
map
.
put
(
"name2"
,
"
李四
"
);
8
map
.
put
(
"name3"
,
"
王五
"
);
9
map
.
put
(
"name4"
,
"
赵六
"
);
10
11
//
获取所有的
key
12
Set
<
String
>
keySet
=
map
.
keySet
();
13
Iterator
<
String
>
iterator
=
keySet
.
iterator
();
14
while
(
iterator
.
hasNext
()){
15
String next
=
iterator
.
next
();
16
System
.
out
.
println
(
next
);
17
}
18
//
获取所有的
value
19
Collection
<
String
>
values
=
map
.
values
();
20
for
(
String value
:
values
) {
21
System
.
out
.
println
(
value
);
22
}
23