Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
wushizhenking
CS-Notes
提交
02f72575
C
CS-Notes
项目概览
wushizhenking
/
CS-Notes
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
C
CS-Notes
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
02f72575
编写于
3月 24, 2018
作者:
C
CyC2018
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
auto commit
上级
09294fa4
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
84 addition
and
5 deletion
+84
-5
notes/Java 容器.md
notes/Java 容器.md
+84
-5
pics/061c29ce-e2ed-425a-911e-56fbba1efce3.jpg
pics/061c29ce-e2ed-425a-911e-56fbba1efce3.jpg
+0
-0
pics/hashMap_u54C8_u5E0C_u7B97_u6CD5_u4F8B_u56FE.png
pics/hashMap_u54C8_u5E0C_u7B97_u6CD5_u4F8B_u56FE.png
+0
-0
未找到文件。
notes/Java 容器.md
浏览文件 @
02f72575
...
...
@@ -266,7 +266,7 @@ private void writeObject(java.io.ObjectOutputStream s)
[
HashMap.java
](
https://github.com/CyC2018/JDK-Source-Code/tree/master/src/HashMap.java
)
### 1.
基本数据
结构
### 1.
存储
结构
使用拉链法来解决冲突,内部包含了一个 Entry 类型的数组 table,数组中的每个位置被当成一个桶。
...
...
@@ -278,6 +278,50 @@ transient Entry[] table;
<div
align=
"center"
>
<img
src=
"../pics//ce039f03-6588-4f0c-b35b-a494de0eac47.png"
width=
"500"
/>
</div><br>
Java 8 使用 Node 类型存储一个键值对,它依然继承自 Entry,因此可以按照上面的存储结构来理解。
```
java
static
class
Node
<
K
,
V
>
implements
Map
.
Entry
<
K
,
V
>
{
final
int
hash
;
final
K
key
;
V
value
;
Node
<
K
,
V
>
next
;
Node
(
int
hash
,
K
key
,
V
value
,
Node
<
K
,
V
>
next
)
{
this
.
hash
=
hash
;
this
.
key
=
key
;
this
.
value
=
value
;
this
.
next
=
next
;
}
public
final
K
getKey
()
{
return
key
;
}
public
final
V
getValue
()
{
return
value
;
}
public
final
String
toString
()
{
return
key
+
"="
+
value
;
}
public
final
int
hashCode
()
{
return
Objects
.
hashCode
(
key
)
^
Objects
.
hashCode
(
value
);
}
public
final
V
setValue
(
V
newValue
)
{
V
oldValue
=
value
;
value
=
newValue
;
return
oldValue
;
}
public
final
boolean
equals
(
Object
o
)
{
if
(
o
==
this
)
return
true
;
if
(
o
instanceof
Map
.
Entry
)
{
Map
.
Entry
<?,?>
e
=
(
Map
.
Entry
<?,?>)
o
;
if
(
Objects
.
equals
(
key
,
e
.
getKey
())
&&
Objects
.
equals
(
value
,
e
.
getValue
()))
return
true
;
}
return
false
;
}
}
```
### 2. 拉链法的工作原理
```
java
...
...
@@ -294,7 +338,15 @@ map.put("vaibhav", 20);
当进行查找时,需要分成两步进行,第一步是先根据 hashcode 计算出所在的桶,第二步是在链表上顺序查找。由于 table 是数组形式的,具有随机读取的特性,因此第一步的时间复杂度为 O(1),而第二步需要在链表上顺序查找,时间复杂度显然和链表的长度成正比。
### 3. 扩容
### 3. 链表转红黑树
应该注意到,从 Java 8 开始,一个桶存储的链表长度大于 8 时会将链表转换为红黑树。
<div
align=
"center"
>
<img
src=
"../pics//061c29ce-e2ed-425a-911e-56fbba1efce3.jpg"
width=
"500"
/>
</div><br>
### 4. 扩容
因为从 Java 8 开始引入了红黑树,因此扩容操作较为复杂,为了便于理解,以下内容使用 Java 7 的内容。
设 HashMap 的 table 长度为 M,需要存储的键值对数量为 N,如果哈希函数满足均匀性的要求,那么每条链表的长度大约为 N/M,因此平均查找次数的数量级为 O(N/M)。
...
...
@@ -374,7 +426,32 @@ void transfer(Entry[] newTable) {
}
```
### 4. capacity 保证为 2 的幂次方
### 5. 确定桶下标
需要三步操作:计算 Key 的 hashCode、高位运算、除留余数法取模。
<div
align=
"center"
>
<img
src=
"../pics//hashMap_u54C8_u5E0C_u7B97_u6CD5_u4F8B_u56FE.png"
width=
"800"
/>
</div><br>
**(一)hashcode()**
```
java
public
final
int
hashCode
()
{
return
Objects
.
hashCode
(
key
)
^
Objects
.
hashCode
(
value
);
}
```
**(二)高位运算**
通过 hashCode() 的高 16 位异或低 16 位,使得数组比较小时,也能保证高低位都参与到了哈希计算中。
```
java
static
final
int
hash
(
Object
key
)
{
int
h
;
return
(
key
==
null
)
?
0
:
(
h
=
key
.
hashCode
())
^
(
h
>>>
16
);
}
```
**(三)除留余数**
令 x = 1<<4,即 x 为 2 的 4 次方,它具有以下性质:
...
...
@@ -403,13 +480,15 @@ y%x : 00000010
拉链法需要使用除留余数法来得到桶下标,也就是需要进行以下计算:hash%capacity,如果能保证 capacity 为 2 的幂次方,那么就可以将这个操作转换位位运算。
以下操作在 Java 8 中没有,但是原理上相同。
```
java
static
int
indexFor
(
int
h
,
int
length
)
{
return
h
&
(
length
-
1
);
}
```
###
5
. null 值
###
6
. null 值
get() 操作需要分成两种情况,key 为 null 和不为 null,从中可以看出 HashMap 允许插入 null 作为键。
...
...
@@ -467,7 +546,7 @@ private V putForNullKey(V value) {
}
```
###
6
. 与 HashTable 的区别
###
7
. 与 HashTable 的区别
-
HashTable 是同步的,它使用了 synchronized 来进行同步。它也是线程安全的,多个线程可以共享同一个 HashTable。HashMap 不是同步的,但是可以使用 ConcurrentHashMap,它是 HashTable 的替代,而且比 HashTable 可扩展性更好。
-
HashMap 可以插入键为 null 的 Entry。
...
...
pics/061c29ce-e2ed-425a-911e-56fbba1efce3.jpg
0 → 100644
浏览文件 @
02f72575
34.0 KB
pics/hashMap_u54C8_u5E0C_u7B97_u6CD5_u4F8B_u56FE.png
0 → 100644
浏览文件 @
02f72575
115.0 KB
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录