Map 常用的实现类如下:

  • Hashtable :Java 早期hash类,线程安全,不支持 null 键和值,因为它的性能不如 ConcurrentHashMap,所以基本不用。
  • HashMap :最常用的hash实现类,线程不安全,支持 null 键和值,多线程中可用 ConcurrentHashMap 替代。
  • TreeMap :基于红黑树的有序 Map,自身实现了按 key 排序,也可以指定 Comparator 来自定义排序。
  • LinkedHashMap :HashMap 的一个子类,按插入顺序排序

HashMap 数据结构

数组+链表+树的方式存储数据,HashMap 底层的数据是数组被成为哈希桶,每个桶存放的是链表,链表中的每个节点,就是 HashMap 中的每个元素。在 JDK 8 当链表长度大于等于8 时,就会转成红黑树的数据结构,以提升查询和插入的效率。

HashMap put方法源码分析

        // 对 key 进行 hash()
return putVal(hash(key), key, value, false, true);
}
static final int hash(Object key) {
int h;
// 对 key 进行 hash() 的具体实现
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
// tab为空则创建
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
// 计算 index,并对 null 做处理
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
// 节点存在 对比key的hash值并调用equals
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
// 判断是否已树化后的链表
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
// 该链为链表
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
// 写入
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
// 超过load factor*current capacity, 调用扩容方法resize
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}

get方法


public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
} /**
* @param hash 通过hash(key)得到的 hash 值,再根据 hash 值在节点数组中寻址
* @param key key 对象,当存在 hash 碰撞时,要逐个比对链表的值是否与传入的值相等
* @return 查找到则返回键值对节点对象,否则返回 null
*/
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n; K k; // 声明节点数组对象、链表的第一个节点对象、循环遍历时遍历到的节点对象、数组长度、节点的键对象
// 获取节点数组、数组长度、通过位运算得到求模结果确定链表的首节点
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
if (first.hash == hash && // 首先比对首节点,如果首节点的 hash 值和 key 的 hash 值相同,并且首节点的键对象和 key 相同(同一内存地址或 equals 结果为true),则返回该节点
((k = first.key) == key || (key != null && key.equals(k))))
return first; // 返回首节点
// 如果首节点比对不相同、那么看看是否存在下一个节点,如果存在的话,可以继续比对,如果不存在就意味着 key 无对应的值
if ((e = first.next) != null) {
// 如果存在下一个节点 e,那么先看首节点是否是个树节点
if (first instanceof TreeNode)
// 如果是首节点是树节点,那么遍历树来查找
return ((TreeNode<K,V>)first).getTreeNode(hash, key); // 如果首节点不是树节点,就说明还是个普通的链表,那么逐个遍历比对即可
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) // 比对时还是先看 hash 值是否相同、再看地址或 equals
return e; // 如果当前节点e的键对象和key相同,那么返回 e
} while ((e = e.next) != null); // 看看是否还有下一个节点,如果有,继续下一轮比对,否则跳出循环
}
}
return null; // 在比对完所有节点后 无匹配的 key,则返回null

HashMap 在 JDK 7 多线程中使用会导致什么问题?

答:HashMap 在 JDK 7 中会导致死循环的问题。因为在 JDK 7 中,多线程进行 HashMap 扩容时会导致链表的循环引用,这个时候使用

get() 获取元素时就会导致死循环,造成 CPU 100% 的情况。

HashMap 在 JDK 7 和 JDK 8 中有哪些不同?

  • 存储结构:JDK 7 使用的是数组 + 链表;JDK 8 使用的是数组 + 链表 + 红黑树。
  • 存放数据的规则:JDK 7 无冲突时,存放数组;冲突时,存放链表;JDK 8 在没有冲突的情况下直接存放数组,有冲突时,当链表长度小于 8 时,存放在单链表结构中,当链表长度大于 8 时,树化并存放至红黑树的数据结构中。
  • 插入数据方式:JDK 7 使用的是头插法(先将原位置的数据移到后 1 位,再插入数据到该位置);JDK 8 使用的是尾插法(直接插入到链表尾部/红黑树)。

【当年笔记】集合之Map的更多相关文章

  1. java学习笔记—集合之Map集合

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Times } p.p2 { margin: 0.0p ...

  2. Go语言学习笔记十三: Map集合

    Go语言学习笔记十三: Map集合 Map在每种语言中基本都有,Java中是属于集合类Map,其包括HashMap, TreeMap等.而Python语言直接就属于一种类型,写法上比Java还简单. ...

  3. Android(java)学习笔记105:Map集合的遍历之键值对对象找键和值

    package cn.itcast_01; import java.util.HashMap; import java.util.Map; import java.util.Set; /* * Map ...

  4. Android(java)学习笔记104:Map集合的遍历之键找值

    package cn.itcast_01; import java.util.HashMap; import java.util.Map; import java.util.Set; /* * Map ...

  5. Android(java)学习笔记103:Map集合的获取功能

    package cn.itcast_01; import java.util.Collection; import java.util.HashMap; import java.util.Map; i ...

  6. Android(java)学习笔记102:Map集合功能概述

    下面通过代码引入Map集合:如下 package cn.itcast_01; import java.util.HashMap; import java.util.Map; /* * 作为学生来说,是 ...

  7. Java笔记(二十三)……Map集合

    Map接口 Map<K,V> 该集合存储的是键值对,成对往集合里存,而且要保证键的唯一性 常用方法 添加 Vput(K key, V value) voidputAll(Map<? ...

  8. Java基础知识强化之集合框架笔记53:Map集合之Map集合的遍历 键值对对象找键和值

    1. Map集合的遍历(键值对对象找键和值) Map -- 夫妻对  思路:  A: 获取所有结婚证的集合  B: 遍历结婚证的集合,得到每一个结婚证  C: 根据结婚证获取丈夫和妻子 转换:  A: ...

  9. Java基础知识强化之集合框架笔记52:Map集合之Map集合的遍历 键找值

    1. Map集合的遍历  Map -- 夫妻对 思路:  A:把所有的丈夫给集中起来.  B:遍历丈夫的集合,获取得到每一个丈夫.  C:让丈夫去找自己的妻子.  转换:  A:获取所有的键  B:遍 ...

  10. Java基础知识强化之集合框架笔记51:Map集合之Map集合的功能概述与测试

    1. Map集合的功能概述 (1)添加功能 V put(K key,V value):添加元素.这个其实还有另一个功能?先不告诉你,等会讲 如果键是第一次存储,就直接存储元素,返回null 如果键不是 ...

随机推荐

  1. Ceph RGW误删index对象恢复

    版本 [root@control1 ~]# ceph -v ceph version 14.2.22 (ca74598065096e6fcbd8433c8779a2be0c889351) nautil ...

  2. find_package()的使用

    find_package()命令是用来查找依赖包的,理想情况下,一句find_package()把一整个依赖包的头文件包含路径.库路径.库名字.版本号等情况都获取到,后续只管用就好了.但实际中往往CM ...

  3. cs 起源 fps 逆向

    1.找到人物坐标X YZ2.找到鼠标X Y3.易语言读取人物坐标4.读取敌人坐标打开控制台服务器与客户端尽量找客户端 找到XYZ5.实时读取敌人坐标6.三角函数转换屏幕坐标FOV 视场角狙击枪找FOV ...

  4. 一份随笔让你了解这个基于Raspberry Pi / 树莓派而设计的工业计算机

    CM4 Sensing是一款基于Raspberry Pi / 树莓派 计算模块4(简称CM4),由 EDATEC 为物联网和数据采集应用而设计的工业计算机.它充分利用了CM4的结构灵活性,解决了CPU ...

  5. Me-and-My-Girlfriend-1

    Me-and-My-Girlfriend-1 目录 Me-and-My-Girlfriend-1 1 信息收集 1.1 端口扫描 1.2 后台目录扫描 1.2.1 目录分析 2 GetShell 2. ...

  6. DESIR队列研究: 早期SpA患者骶髂关节放射学结构损伤的不同定义对结构损伤变化的敏感性

    DESIR队列研究: 早期SpA患者骶髂关节放射学结构损伤的不同定义对结构损伤变化的敏感性 EULAR2015; PresentID: THU0356 SENSITIVITY TO CHANGE OF ...

  7. LeetCode-807 保持城市天际线

    来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/max-increase-to-keep-city-skyline 题目描述 在二维数组grid ...

  8. [UTCTF2020]basic_crypto

    [UTCTF2020]basic_crypto 题目: 01010101 01101000 00101101 01101111 01101000 00101100 00100000 01101100 ...

  9. 完全机器模拟浏览器操作自动刷网课!不怕被封!!-----python基于selenium实现超星学习通刷视频网课

    (使用过程中有小伙伴反映如果课程的第一章是空白的页面会报错,我当时做的时候是根据我自己的课程,没有第一节是空页面的现象,这个以后有时间我再改一下吧,或者小伙伴自己修改一下也可) 原谅我这个标题党,对叭 ...

  10. cuda+pytorch环境安装

    本机cuda版本为v11.5 conda install cudatoolkit 使用 CUDA 11.3版本的配置 conda install pytorch==1.11.0 torchvision ...