0
点赞
收藏
分享

微信扫一扫

Java - HashMap


Map定义

Map is called key-value collection, each map element contains key and value.

Map格式

Map Format: { key1=value1, key2=value2, k3=value3, ... }

key is unique. Repeat assign value for the same key, the following value will override the previous value.

map.put("name", "bill");
map.put("name", "jack");

key named name will have value as jack.

HashMap vs HashTable

HashMap

HashTable

同步

no

yes

安全

no

yes (使用 synchorized修饰)

效率

高 O(1)


允许空键

yes

no

数据结构

数组+链表

数组+链表 (<jdk1.8) 数组+链表+红黑树(>= jdk1.8)

重复

no

yes

初始化

16

11

增长

new = 2 * old (扩容1倍)

new = 2 * old + 1 (2倍 加 1)

执行效率

JDK 1.5 推出CurrentHashMap。CurrentHashMap将HashMap分片(默认为16片),对每一片加锁(即分段锁),通过key.hashCode判断对哪一片加锁。

效率:HashMap > CurrentHashMap (分段锁) > HashTable (整个加锁)

HashMap数据结构

  • < JDK 1.8,Table数组 + Entry链表
  • ≥ JDK 1.8,Table数组 + Entry链表/红黑树

a. 数组+链表:输入元素时首先根据key的hashcode计算hash值,根据hash值得到元素在数组中的位置。如果该位置有值,则该位置以链表的形式存放,新加入的元素放在链尾。如果该位置为空,就当新元素放在此位置。

b. 红黑树:链表中节点超过8个时,链表会转为红黑树来提高查询效率。复杂度从O(n) 变为O(logn)。

public class HashMapDemo {
public static void main(String[] args) {
HashMapDemo map = new HashMapDemo();
map.put("刘一", "刘一");
map.put("陈二", "陈二");
map.put("张三", "张三");
map.put("李四", "李四");
map.put("王五", "王五");
map.put("悟空", "悟空");
}

public static void put (String key, String value) {
System.out.println(key + ":" + key.hashCode() + ":" + Math.abs(key.hashCode()%15));
}
}
/** 运行结果://刘一、张三、悟空的hasdCode相同。因此,key值不同,hashCode可以相同。
* 刘一:671464:4
* 陈二:1212740:5
* 张三:774889:4
* 李四:842061:6
* 王五:937065:0
* 悟空:798139:4
*/

CurrentHashMap

CurrentHashMap默认分片为16片,即16个segment。每个Segment包含多个HashEntry列表数组。

一个Key需要经过3次hash映射,才能确定最终位置。

第一次Hash映射:h1=hash1(key)

第二次Hash映射:h2=hash2(h1高几位),确定元素存放在哪个segment。

第三次Hash映射:h3=hash3(h1) 通过h3确定元素放在哪个HashEntry。

面试题

阐述put过程

第一步:寻找索引位置。计算方法:index = hashcode%数组长度。刘一/张三/悟空在hashmap中的索引值为4。

第二步:将节点依次插入单向链表。

Java - HashMap_数据结构

为何使用数组+链表/红黑树

数组大小固定,对key值散列后得到下标。

下标相同即发生冲突(不同key值,索引相同),采用链表对节点链式存放。

链表与红黑树的相互转换,方便于扩容/收缩。

单链表转为红黑树:单链表长度≥8

红黑树转为单链表:红黑树节点≤6

何为红黑树

红黑树是二叉树(树有序、查询效率高、O(logn)),单向链表查复杂度为O(n),左右高度差≤1

HashMap如何扩容

实际长度 > lengh * loadFactor (默认:16 * 0.75)时,HashMap会扩容,长度为原来2倍。

基于时间/空间因素,默认负载因子为0.75。

Map转为JavaBean

hutool BeanUtil

举报

相关推荐

0 条评论