Java集合03——你不得不了解的Map
Map 在面试中永远是一个绕不开的点,本文将详细讲解Map的相关内容。关注公众号「Java面典」了解更多 Java 知识点。
Map
- Map 是一个键值对(key-value)映射接口;
- 映射中不能包含重复的键,每个键最多只能映射到一个值;
- Map 允许以键集(keySet())、值集(valueSet())或键-值映射关系集(entrySet())的形式查看某个映射的内容。
HashMap
特点
- 根据 key 的 hashCode 存储数据,大多数情况下(hash冲突时除外)可以直接定位到值;
- HashMap具有较快的随机读取速度,遍历速度不可控;
- 一个 HashMap 对象中最多只允许一条记录的键为 null,允许多条记录的值为 null;
- HashMap是非线程安全的。
实现

可以看出 HashMap 其实是一个数组 + 单向链表组成。
容量
- capacity:当前数组容量(默认16),始终保持 2^n,可以扩容,扩容后数组大小为当前的 2 倍;
- loadFactor:负载因子,默认为 0.75;
- threshold:扩容阈值,等于 capacity * loadFactor。
Java8实现

从 Java8 开始,Java 对 HashMap 的实现有了一定的改变,开始引入红黑树,所以其结构变成了 数组 + 链表 + 红黑树组成。
原因:当发生 hash 冲突时,在链表中查询 Node 的时间复杂度为 O(n),为了降低时间复杂度,引入红黑树,时间复杂度变为 O(logN)。
容量:除了Java7中的容量相关参数外,Java8为了引入红黑树,还引入了另外几个容量相关的变量。
- static final int TREEIFY_THRESHOLD = 8:链表转树阈值。当链表长度 > 该值时,则将链表转换成红黑树;
- static final int UNTREEIFY_THRESHOLD = 6:树还原链表阈值。当红黑树内节点数量 < 6时,则将红黑树转换成链表;
- static final int MIN_TREEIFY_CAPACITY = 64:最小树化阈值。当哈希表中的容量 > 该值时,才允许链表转化为红黑树。否则将直接扩容。为了避免进行扩容、树形化选择的冲突,这个值不能小于 4 * TREEIFY_THRESHOLD。
ConcurrentHashMap
特点
- ConcurrentHashMap 其实就是一个线程安全的HashMap;
- ConcurrentHashMap key 和 value 均不允许为 null。
网上关于key 和 value 不允许为 null 的解释是这样描述的:如果map.get(key)return null,则无法检测到该键是否显式映射到 null 该键。在非并行映射中,您可以通过进行检查 map.contains(key),但在并行映射中,两次调用之间的映射可能已更改。
实现
[ConcurrentHashMap.png]
- ConcurreuntHashMap 实现和 HashMap 差不多的,但是为了支持并发操作,引入了 Segment,ConcurreuntHashMap 由一个 Segment 数组组成;
- Segment 通过继承 ReentrantLock 来进行加锁,Segment 数组就相当于是 ConcurreuntHashMap 的分段锁,每次操作只用锁住对应的 Segment 就行了;
- Segment 内部由 HashMap 组成;
- concurrencyLevel:并行级别,默认16。其实就是 ConcurreuntHashMap 由长度为 16 的 Segment 组成,所以可以理解为 ConcurreuntHashMap 默认同时可以支持最多 16 个线程并发写。Segment 数组可以在初始化的时候指定,初始化后不可扩容。
Java8实现

和 HashMap 一样, ConcurrentHashMap 在 Java8 中也引入了红黑树的机制。在这里就不再赘述了。
LinkedHashMap

LinkedHashMap 是 HashMap 的一个子类,它记录了元素插入的顺序,能够保证在使用迭代器遍历的时候,先插入的元素先获取。也可在构造时带参数,按照访问次序排序。
WeakHashMap
特点
- WeakHashMap 键值都可以是null;
- WeakHashMap 的键是“弱键”。当某个键不再正常使用时,会被从 WeakHashMap 中被自动移除。
弱键原理
- 弱键通过 WeakReference 和 ReferenceQueue 实现,
- WeakHashMap 的 key 是 WeakReference 类型的, ReferenceQueue是一个队列,它会保存被GC回收的“弱键”;
- 当某“弱键”不再被其它对象引用,并被GC回收时,这个“弱键”也同时会被添加到 ReferenceQueue(queue) 队列中;
- 当再次操作 WeakHashMap 时,会先同步 table 和 queue 。table 中保存了全部的键值对,而 queue 中保存被 GC 回收的键值对;同步它们,就是删除 table 中被 GC 回收的键值对。
主要变量
- table:是一个Entry[]数组类型,用于存储键值对;
- size: 表示 WeakHashMap 的大小;
- threshold :阈值,用于判断是否需要调整容量,threshold的值="容量*加载因子";
- loadFactor: 加载因子;
- modCount:是用来实现fail-fast机制的
- queue:保存的是“已被GC清除”的“弱引用的键”。
TreeMap
- TreeMap 实现 SortedMap 接口,能够把它保存的记录根据键排序;
- 默认按照键值升序排序,也可指定排序的比较器;
- 在使用 TreeMap 时,key 必须实现 Comparable 接口或者在构造 TreeMap 传入自定义的 Comparator,否则会在运行时抛出 java.lang.ClassCastException 类型的异常。
Hashtable
- Hashtable 继承自 Dictionary 接口,相当于介于 HashMap 与 ConcurrentHashMap 之间的一种哈希表;
- 相较于 HashMap 而言,他是线程安全的,同时与 ConcurrentHashMap 一样,key vlaue 均不能为null;
- 相较于 ConcurrentHashMap 而言,Hashtable 不支持多线程同时操作。
- 所以在在单线程环境一般使用 HashMap,而在多线程环境中,使用 ConcurrentHashMap 。
Java集合系列推荐
Java集合03——你不得不了解的Map的更多相关文章
- Java集合的Stack、Queue、Map的遍历
Java集合的Stack.Queue.Map的遍历 在集合操作中,常常离不开对集合的遍历,对集合遍历一般来说一个foreach就搞定了,但是,对于Stack.Queue.Map类型的遍历,还是有一 ...
- Java集合:List、Set和Map的区别,ArrayList和LinkedList有何区别..........
一.数组和集合的区别: 数组是大小固定的,并且同一个数组只能存放类型一样的数据(基本类型/引用类型): 集合可以存储和操作数目不固定的一组数据. 所有的JAVA集合都位于 java.util包中! J ...
- Java集合中List、Set以及Map
概述: List , Set, Map都是接口:List , Set继承至Collection接口,Map为独立接口 Set下有HashSet,LinkedHashSet,TreeSet List下有 ...
- Java 集合(List、Set、Map 等)相关问答归纳再整理
写在最前面 这个项目是从20年末就立好的 flag,经过几年的学习,回过头再去看很多知识点又有新的理解.所以趁着找实习的准备,结合以前的学习储备,创建一个主要针对应届生和初学者的 Java 开源知识项 ...
- java集合框架--List、Set、Map
1.List:有序的 collection(也称为序列).此接口可以对列表中每个元素的插入位置进行精确地控制.可以根据元素的在列表中的位置访问元素,并搜索列表中的元素.列表允许重复的元素. ...
- java集合: List、Set、Map总结 + HashMap/Hashtable 差别
List:(有序,能够反复)通过下标索引 ----ArrayList 可变数组,随机查找 ----LinkedList 链表,不论什么位置插入删除快 ----Vecto ...
- java集合框架复习----(4)Map、List、set
文章目录 五.Map集合[重要] 1.hashMap 六.Collections工具类 总结 集合的概念 List集合 set集合: Map集合 Collection 五.Map集合[重要] 特点: ...
- java 集合(list、set、map)的特点
集合相关的类有一大堆,一般也只用到常用的方法增删改查,而且它它们的方法名也基本一样,所以一直都不知道什么时候用什么集合, 今天趁有空特意从网上整理资料方便日后回忆. 一.List:.有顺序以线性方式存 ...
- Java集合总结(二):Map和Set
集合类的架构图: HashMap 内部维护一个链表数组做哈希表,默认大小为16,最大值可以为2^30,默认负载因子0.75. 可以通过构造方法指定初始大小和负载因子,当键值对个数大于等于临界值thre ...
随机推荐
- QT中的QQueue类、C++中的queue类
C++中的queue 实现一种先进先出的数据结构,是一个模板类 头文件 #include<queue> queue<int> Q; //定义一个int型队列 Q.empty() ...
- C++ const成员变量和成员函数(常成员函数)
在类中,如果你不希望某些数据被修改,可以使用const关键字加以限定.const 可以用来修饰成员变量和成员函数. const成员变量 const 成员变量的用法和普通 const 变量的用法相似,只 ...
- Qt QString 与 const char* 类型的转换
QString DATA; std::string str = DATA.toStdString(); const char* ch = str.c_str();
- Qt foreach关键字用法
Qt提供一个关键字 foreach (实际是 <QtGlobal> 里定义的一个宏)用于方便地访问容器里所有数据项. foreach 关键字用于遍历容路中所有的项,使用 foreach 的 ...
- 杂谈php之什么是cgi,fastcgi,fpm,cli,mod
杂谈PHP极少关注的问题 本话题来自于我使用PHP进行网页爬虫的一次经历.对于一个web开发者来说,PHP解释器本身却知之甚小,实在是惭愧呐! 首先这个话题要从几个提问开始. PHP是什么? 外文名: ...
- 有用户及目录判断的删除文件内容的Shell脚本
[root@localhost Qingchu]# cat Qingchu_version2.sh #!/bin/bash #描述: # 清除脚本! #作者:孤舟点点 #版本:2.0 #创建时间:-- ...
- Luogu_2878_[USACO07JAN]保护花朵Protecting the Flowers
题目描述 Farmer John went to cut some wood and left N (2 ≤ N ≤ 100,000) cows eating the grass, as usual. ...
- python中字符串操作--截取,查找,替换
python中,对字符串的操作是最常见的,python对字符串操作有自己特殊的处理方式. 字符串的截取 python中对于字符串的索引是比较特别的,来感受一下: s = '123456789' #截取 ...
- iOS开发之多线程(NSThread、NSOperation、GCD)
整理一些多线程相关的知识. 并行 & 并发 1.并行:并行是相对于多核而言的,几个任务同时执行.2.并发:并发是相对于单核而言的,几个任务之间快速切换运行,看起来像是"同时" ...
- docker运行mysql主从备份,读写分离
1)从Docker官方下拉MySQL的image 打开https://hub.docker.com/ 搜索mysql 在docker中运行 默认tag为latest docker pull mysql ...