本篇文章为你整理了Map(map医学上)的详细内容,包含有map测试 map医学上 mapreduce map函数的用法python Map,希望能帮助你了解 Map。
Java 全栈知识体系 ❁导航 ♥面试 ✿导读 JavaJavaJava 面向对象和基础 Java 面向对象基础 Java 基础知识体系 Java进阶 - 集合框架 Java 集合框架详解 Java进阶 - 并发框架 Java 并发知识体系 Java 并发理论基础 Java 并发线程基础 J.U.C 知识体系与详解 Java进阶 - IO框架 Java IO/NIO/AIO详解 Java进阶 - 新版本特性 Java 8 特性详解 Java 8 以上版本特性体系 Java 8 升Java 11特性必读 Java 11 升Java 17特性必读 Java进阶 - JVM相关 Java 类加载机制 Java 字节码和增强技术 JVM 内存结构详解 JVM 垃圾回收机制 Java 调试排错相关 算法算法算法基础和思想 数据结构基础 常见排序算法 算法思想 一些领域算法 安全算法 字符串匹配算法 分布式系统算法 海量数据处理 负载均衡算法 推荐算法 数据挖掘算法 ID生成算法 其它算法相关 头脑风暴 数据库数据库数据库基础和原理 数据库原理 SQL语言 SQL 数据库 MySQL 详解 NoSQL 数据库 Redis 详解 MongoDB 详解 ElasticSearch 详解 开发开发开发 - 常用开发基础 常用类库详解 正则表达式详解 CRON表达式详解 网络协议和工具详解 安全相关详解 开发 - 质量保障 单元测试详解 统一风格详解 质量管理详解 开发 - 代码重构 代码重构相关 SpringSpringSpring Framework(v5.3) Spring框架知识体系 Spring框架组成 控制反转(IOC) 面向切面编程(AOP) SpringMVC SpringBoot系列(v2.5) SpringBoot知识体系 SpringBoot入门 SpringBoot接口设计和实现 SpringBoot集成MySQL SpringBoot集成ShardingJDBC SpringBoot集成Redis SpringBoot集成Postgre SpringBoot集成ElasticSearch SpringBoot集成Socket SpringBoot定时任务 SpringBoot后端视图 SpringBoot监控 SpringBoot进阶 框架中间件框架中间件Web 容器 Tomcat 源码详解 ORM 框架 MyBatis 源码详解 分表分库框架 ShardingSphere 详解 架构架构架构基础和技术点 架构知识体系 从角色视角看架构 从分层视角看架构 从演化视角看架构 从模式视角看架构 高并发之缓存 高并发之限流 高并发之降级和熔断 高可用之负载均衡 高可用之容灾备份 分布式系统 分布式理论和一致性算法 全局唯一ID实现方案 分布式锁及实现方案 分布式事务及实现方案 分布式任务及实现方案 分布式会话及实现方案 微服务系统 微服务系统和设计 系统设计之商业业务平台 秒杀抽奖相关设计 电商交易相关设计 仓储物流相关设计 拉新投放相关设计 其它综合相关设计 系统设计之数据仓库平台 数据库架构相关设计 数据同步相关设计 数据仓库相关设计 数据治理相关设计 工具部署工具部署 开发工具 Git详解 Linux Docker 项目 方法论方法论开发理论 开发原则(SOLID) 分布式理论(CAP) 分布式理论(BASE) 事务理论(ACID) 微服务理论(康威定律) 开源协议 常见开源协议详解 知识共享许可协议 国产开源木兰协议 代码规范 阿里巴巴 Java开发手册 Google Java 编程风格指南 Twitter Java代码规范 开发流程 软件生命周期与传统模型 结合测试演化的过程模型 敏捷开发项目管理理论 敏捷之极限编程(XP) 敏捷之Scrum Kanban 敏捷实践之测试驱动开发 设计模式 设计模式详解 系统认证 CMMI 认证 等级保护认证 ISO27001认证 产品团队产品团队技术之外 技术之外应该思考什么 个人相关 个人成长和认知 产品相关 产品设计和思考 团队相关 管对管理和成长 其它相关 其它软实力等 关于 ❁导航 ♥面试 ✿导读 JavaJavaJava 面向对象和基础 Java 面向对象基础 Java 基础知识体系 Java进阶 - 集合框架 Java 集合框架详解 Java进阶 - 并发框架 Java 并发知识体系 Java 并发理论基础 Java 并发线程基础 J.U.C 知识体系与详解 Java进阶 - IO框架 Java IO/NIO/AIO详解 Java进阶 - 新版本特性 Java 8 特性详解 Java 8 以上版本特性体系 Java 8 升Java 11特性必读 Java 11 升Java 17特性必读 Java进阶 - JVM相关 Java 类加载机制 Java 字节码和增强技术 JVM 内存结构详解 JVM 垃圾回收机制 Java 调试排错相关 算法算法算法基础和思想 数据结构基础 常见排序算法 算法思想 一些领域算法 安全算法 字符串匹配算法 分布式系统算法 海量数据处理 负载均衡算法 推荐算法 数据挖掘算法 ID生成算法 其它算法相关 头脑风暴 数据库数据库数据库基础和原理 数据库原理 SQL语言 SQL 数据库 MySQL 详解 NoSQL 数据库 Redis 详解 MongoDB 详解 ElasticSearch 详解 开发开发开发 - 常用开发基础 常用类库详解 正则表达式详解 CRON表达式详解 网络协议和工具详解 安全相关详解 开发 - 质量保障 单元测试详解 统一风格详解 质量管理详解 开发 - 代码重构 代码重构相关 SpringSpringSpring Framework(v5.3) Spring框架知识体系 Spring框架组成 控制反转(IOC) 面向切面编程(AOP) SpringMVC SpringBoot系列(v2.5) SpringBoot知识体系 SpringBoot入门 SpringBoot接口设计和实现 SpringBoot集成MySQL SpringBoot集成ShardingJDBC SpringBoot集成Redis SpringBoot集成Postgre SpringBoot集成ElasticSearch SpringBoot集成Socket SpringBoot定时任务 SpringBoot后端视图 SpringBoot监控 SpringBoot进阶 框架中间件框架中间件Web 容器 Tomcat 源码详解 ORM 框架 MyBatis 源码详解 分表分库框架 ShardingSphere 详解 架构架构架构基础和技术点 架构知识体系 从角色视角看架构 从分层视角看架构 从演化视角看架构 从模式视角看架构 高并发之缓存 高并发之限流 高并发之降级和熔断 高可用之负载均衡 高可用之容灾备份 分布式系统 分布式理论和一致性算法 全局唯一ID实现方案 分布式锁及实现方案 分布式事务及实现方案 分布式任务及实现方案 分布式会话及实现方案 微服务系统 微服务系统和设计 系统设计之商业业务平台 秒杀抽奖相关设计 电商交易相关设计 仓储物流相关设计 拉新投放相关设计 其它综合相关设计 系统设计之数据仓库平台 数据库架构相关设计 数据同步相关设计 数据仓库相关设计 数据治理相关设计 工具部署工具部署 开发工具 Git详解 Linux Docker 项目 方法论方法论开发理论 开发原则(SOLID) 分布式理论(CAP) 分布式理论(BASE) 事务理论(ACID) 微服务理论(康威定律) 开源协议 常见开源协议详解 知识共享许可协议 国产开源木兰协议 代码规范 阿里巴巴 Java开发手册 Google Java 编程风格指南 Twitter Java代码规范 开发流程 软件生命周期与传统模型 结合测试演化的过程模型 敏捷开发项目管理理论 敏捷之极限编程(XP) 敏捷之Scrum Kanban 敏捷实践之测试驱动开发 设计模式 设计模式详解 系统认证 CMMI 认证 等级保护认证 ISO27001认证 产品团队产品团队技术之外 技术之外应该思考什么 个人相关 个人成长和认知 产品相关 产品设计和思考 团队相关 管对管理和成长 其它相关 其它软实力等 关于 Java 基础
Java 基础 - 面向对象 Java 基础 - 知识点 Java 基础 - 图谱 Q/A Java 基础 - 泛型机制详解 Java 基础 - 注解机制详解 Java 基础 - 异常机制详解 Java 基础 - 反射机制详解 Java常用机制 - SPI机制详解 Java 集合框架
Collection 类关系图 Collection - ArrayList 源码解析 Collection - LinkedList源码解析 Collection - Stack Queue 源码解析 Collection - PriorityQueue源码解析 Map - HashSet HashMap 源码解析 Map - LinkedHashSet Map源码解析 Map - TreeSet TreeMap 源码解析 Map - WeakHashMap源码解析 Java 多线程与并发
♥Java并发知识体系详解♥ Java 并发 - 理论基础 Java 并发 - 线程基础 Java并发 - Java中所有的锁 关键字: synchronized详解 关键字: volatile详解 关键字: final详解 JUC - 类汇总和学习指南 JUC原子类: CAS, Unsafe和原子类详解 JUC锁: LockSupport详解 JUC锁: 锁核心类AQS详解 JUC锁: ReentrantLock详解 JUC锁: ReentrantReadWriteLock详解 JUC集合: ConcurrentHashMap详解 JUC集合: CopyOnWriteArrayList详解 JUC集合: ConcurrentLinkedQueue详解 JUC集合: BlockingQueue详解 JUC线程池: FutureTask详解 JUC线程池: ThreadPoolExecutor详解 JUC线程池: ScheduledThreadPoolExecutor详解 JUC线程池: Fork/Join框架详解 JUC工具类: CountDownLatch详解 JUC工具类: CyclicBarrier详解 JUC工具类: Semaphore详解 JUC工具类: Phaser详解 JUC工具类: Exchanger详解 Java 并发 - ThreadLocal详解 Java IO/NIO/AIO
♥Java IO知识体系详解♥ Java IO - 分类(传输,操作) Java IO - 设计模式(装饰者模式) Java IO - 源码: InputStream Java IO - 源码: OutputStream Java IO - 常见类使用 IO 模型 - Unix IO 模型 Java IO - BIO 详解 Java NIO - 基础详解 Java NIO - IO多路复用详解 Java AIO - 异步IO详解 Java N(A)IO - 框架: Netty Java NIO - 零拷贝实现 Java8 特性详解
♥Java8特性知识体系详解♥ Java 8 - 函数编程(lambda表达式) Java 8 - Optional类深度解析 Java 8 - 默认方法 Java 8 - 类型注解 Java 8 - 重复注解 Java 8 - 类型推断优化 Java 8 - JRE精简 Java 8 - 移除Permgen Java 8 - StampedLock Java 8 - LocalDate/LocalDateTime Java 8 - JavaFx 2.0 Java 8 - 其它更新: 字符串,base64,... Java8 以上特性概述
♥Java8+特性知识体系详解♥ Java 8 升Java 11 重要特性必读 Java 11 升Java 17 重要特性必读 Java 9 新特性概述 Java 10 新特性概述 Java 11 新特性概述 Java 12 新特性概述 Java 13 新特性概述 Java 14 新特性概述 Java 15 新特性概述 Java 16 新特性概述 Java 17 新特性概述 JVM相关
♥JVM相关知识体系详解♥ JVM 基础 - 类字节码详解 JVM 基础 - 字节码的增强技术 JVM 基础 - Java 类加载机制 JVM 基础 - JVM 内存结构 JVM 基础 - Java 内存模型引入 JVM 基础 - Java 内存模型详解 GC - Java 垃圾回收基础知识 GC - Java 垃圾回收器之G1详解 GC - Java 垃圾回收器之ZGC详解 GC - Java 垃圾回收器之CMS GC问题分析与解决 调试排错 - JVM 调优参数 调试排错 - Java 内存分析之堆内存和MetaSpace内存 调试排错 - Java 内存分析之堆外内存 调试排错 - Java 线程分析之线程Dump分析 调试排错 - Java 问题排查之Linux命令 调试排错 - Java 问题排查之工具单 调试排错 - Java 问题排查之JVM可视化工具 调试排错 - Java 问题排查之应用在线调试Arthas 调试排错 - Java 问题排查之使用IDEA本地调试和远程调试 调试排错 - Java动态调试技术原理 Java其它相关
Awesome Java Better Java # Map - HashSet HashMap 源码解析本文主要对Map - HashSet HashMap进行源码解析。@pdai
Map - HashSet HashMap 源码解析Java7 HashMap概述get()put()remove()Java8 HashMapput 过程分析数组扩容get 过程分析HashSet# Java7 HashMap# 概述之所以把HashSet和HashMap放在一起讲解,是因为二者在Java里有着相同的实现,前者仅仅是对后者做了一层包装,也就是说HashSet里面有一个HashMap(适配器模式)。因此本文将重点分析HashMap。
HashMap实现了Map接口,即允许放入key为null的元素,也允许插入value为null的元素;除该类未实现同步外,其余跟Hashtable大致相同;跟TreeMap不同,该容器不保证元素顺序,根据需要该容器可能会对元素重新哈希,元素的顺序也会被重新打散,因此不同时间迭代同一个HashMap的顺序可能会不同。 根据对冲突的处理方式不同,哈希表有两种实现方式,一种开放地址方式(Open addressing),另一种是冲突链表方式(Separate chaining with linked lists)。Java7 HashMap采用的是冲突链表方式。
从上图容易看出,如果选择合适的哈希函数,put()和get()方法可以在常数时间内完成。但在对HashMap进行迭代时,需要遍历整个table以及后面跟的冲突链表。因此对于迭代比较频繁的场景,不宜将HashMap的初始大小设的过大。
有两个参数可以影响HashMap的性能: 初始容量(inital capacity)和负载系数(load factor)。初始容量指定了初始table的大小,负载系数用来指定自动扩容的临界值。当entry的数量超过capacity*load_factor时,容器将自动扩容并重新哈希。对于插入元素较多的场景,将初始容量设大可以减少重新哈希的次数。
将对象放入到HashMap或HashSet中时,有两个方法需要特别关心: hashCode()和equals()。hashCode()方法决定了对象会被放到哪个bucket里,当多个对象的哈希值冲突时,equals()方法决定了这些对象是否是“同一个对象”。所以,如果要将自定义的对象放入到HashMap或HashSet中,需要**@Override** hashCode()和equals()方法。
# get()get(Object key)方法根据指定的key值返回对应的value,该方法调用了getEntry(Object key)得到相应的entry,然后返回entry.getValue()。因此getEntry()是算法的核心。 算法思想是首先通过hash()函数得到对应bucket的下标,然后依次遍历冲突链表,通过key.equals(k)方法来判断是否是要找的那个entry。
上图中hash(k) (table.length-1)等价于hash(k)%table.length,原因是HashMap要求table.length必须是2的指数,因此table.length-1就是二进制低位全是1,跟hash(k)相与会将哈希值的高位全抹掉,剩下的就是余数了。
//getEntry()方法
final Entry K,V getEntry(Object key) {
......
int hash = (key == null) ? 0 : hash(key);
for (Entry K,V e = table[hash (table.length-1)];//得到冲突链表
e != null; e = e.next) {//依次遍历冲突链表中的每个entry
Object k;
//依据equals()方法判断是否相等
if (e.hash == hash
((k = e.key) == key (key != null key.equals(k))))
return e;
return null;
# put()put(K key, V value)方法是将指定的key, value对添加到map里。该方法首先会对map做一次查找,看是否包含该元组,如果已经包含则直接返回,查找过程类似于getEntry()方法;如果没有找到,则会通过addEntry(int hash, K key, V value, int bucketIndex)方法插入新的entry,插入方式为头插法。
//addEntry()
void addEntry(int hash, K key, V value, int bucketIndex) {
if ((size = threshold) (null != table[bucketIndex])) {
resize(2 * table.length);//自动扩容,并重新哈希
hash = (null != key) ? hash(key) : 0;
bucketIndex = hash (table.length-1);//hash%table.length
//在冲突链表头部插入新的entry
Entry K,V e = table[bucketIndex];
table[bucketIndex] = new Entry (hash, key, value, e);
size++;
# remove()remove(Object key)的作用是删除key值对应的entry,该方法的具体逻辑是在removeEntryForKey(Object key)里实现的。removeEntryForKey()方法会首先找到key值对应的entry,然后删除该entry(修改链表的相应引用)。查找过程跟getEntry()过程类似。
//removeEntryForKey()
final Entry K,V removeEntryForKey(Object key) {
......
int hash = (key == null) ? 0 : hash(key);
int i = indexFor(hash, table.length);//hash (table.length-1)
Entry K,V prev = table[i];//得到冲突链表
Entry K,V e = prev;
while (e != null) {//遍历冲突链表
Entry K,V next = e.next;
Object k;
if (e.hash == hash
((k = e.key) == key (key != null key.equals(k)))) {//找到要删除的entry
modCount++; size--;
if (prev == e) table[i] = next;//删除的是冲突链表的第一个entry
else prev.next = next;
return e;
prev = e; e = next;
return e;
# Java8 HashMapJava8 对 HashMap 进行了一些修改,最大的不同就是利用了红黑树,所以其由 数组+链表+红黑树 组成。
根据 Java7 HashMap 的介绍,我们知道,查找的时候,根据 hash 值我们能够快速定位到数组的具体下标,但是之后的话,需要顺着链表一个个比较下去才能找到我们需要的,时间复杂度取决于链表的长度,为 O(n)。
为了降低这部分的开销,在 Java8 中,当链表中的元素达到了 8 个时,会将链表转换为红黑树,在这些位置进行查找的时候可以降低时间复杂度为 O(logN)。
来一张图简单示意一下吧:
注意,上图是示意图,主要是描述结构,不会达到这个状态的,因为这么多数据的时候早就扩容了。
下面,我们还是用代码来介绍吧,个人感觉,Java8 的源码可读性要差一些,不过精简一些。
Java7 中使用 Entry 来代表每个 HashMap 中的数据节点,Java8 中使用 Node,基本没有区别,都是 key,value,hash 和 next 这四个属性,不过,Node 只能用于链表的情况,红黑树的情况需要使用 TreeNode。
我们根据数组元素中,第一个节点数据类型是 Node 还是 TreeNode 来判断该位置下是链表还是红黑树的。
# put 过程分析
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
// 第四个参数 onlyIfAbsent 如果是 true,那么只有在不存在该 key 时才会进行 put 操作
// 第五个参数 evict 我们这里不关心
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node K,V [] tab; Node K,V p; int n, i;
// 第一次 put 值的时候,会触发下面的 resize(),类似 java7 的第一次 put 也要初始化数组长度
// 第一次 resize 和后续的扩容有些不一样,因为这次是数组从 null 初始化到默认的 16 或自定义的初始容量
if ((tab = table) == null (n = tab.length) == 0)
n = (tab = resize()).length;
// 找到具体的数组下标,如果此位置没有值,那么直接初始化一下 Node 并放置在这个位置就可以了
if ((p = tab[i = (n - 1) hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {// 数组该位置有数据
Node K,V e; K k;
// 首先,判断该位置的第一个数据和我们要插入的数据,key 是不是 相等 ,如果是,取出这个节点
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) {
// 插入到链表的最后面(Java7 是插入到链表的最前面)
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
// TREEIFY_THRESHOLD 为 8,所以,如果新插入的值是链表中的第 8 个
// 会触发下面的 treeifyBin,也就是将链表转换为红黑树
if (binCount = TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
// 如果在该链表中找到了 相等 的 key(== 或 equals)
if (e.hash == hash
((k = e.key) == key (key != null key.equals(k))))
// 此时 break,那么 e 为链表中[与要插入的新值的 key 相等 ]的 node
break;
p = e;
// e!=null 说明存在旧值的key与要插入的key 相等
// 对于我们分析的put操作,下面这个 if 其实就是进行 值覆盖 ,然后返回旧值
if (e != null) {
V oldValue = e.value;
if (!onlyIfAbsent oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
++modCount;
// 如果 HashMap 由于新插入这个值导致 size 已经超过了阈值,需要进行扩容
if (++size threshold)
resize();
afterNodeInsertion(evict);
return null;
和 Java7 稍微有点不一样的地方就是,Java7 是先扩容后插入新值的,Java8 先插值再扩容,不过这个不重要。
# 数组扩容resize() 方法用于初始化数组或数组扩容,每次扩容后,容量为原来的 2 倍,并进行数据迁移。
final Node K,V [] resize() {
Node K,V [] oldTab = table;
int oldCap = (oldTab == null) ? 0 : oldTab.length;
int oldThr = threshold;
int newCap, newThr = 0;
if (oldCap 0) { // 对应数组扩容
if (oldCap = MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
// 将数组大小扩大一倍
else if ((newCap = oldCap 1) MAXIMUM_CAPACITY
oldCap = DEFAULT_INITIAL_CAPACITY)
// 将阈值扩大一倍
newThr = oldThr 1; // double threshold
else if (oldThr 0) // 对应使用 new HashMap(int initialCapacity) 初始化后,第一次 put 的时候
newCap = oldThr;
else {// 对应使用 new HashMap() 初始化后,第一次 put 的时候
newCap = DEFAULT_INITIAL_CAPACITY;
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
if (newThr == 0) {
float ft = (float)newCap * loadFactor;
newThr = (newCap MAXIMUM_CAPACITY ft (float)MAXIMUM_CAPACITY ?
(int)ft : Integer.MAX_VALUE);
threshold = newThr;
// 用新的数组大小初始化新的数组
Node K,V [] newTab = (Node K,V [])new Node[newCap];
table = newTab; // 如果是初始化数组,到这里就结束了,返回 newTab 即可
if (oldTab != null) {
// 开始遍历原数组,进行数据迁移。
for (int j = 0; j oldCap; ++j) {
Node K,V e;
if ((e = oldTab[j]) != null) {
oldTab[j] = null;
// 如果该数组位置上只有单个元素,那就简单了,简单迁移这个元素就可以了
if (e.next == null)
newTab[e.hash (newCap - 1)] = e;
// 如果是红黑树,具体我们就不展开了
else if (e instanceof TreeNode)
((TreeNode K,V )e).split(this, newTab, j, oldCap);
else {
// 这块是处理链表的情况,
// 需要将此链表拆成两个链表,放到新的数组中,并且保留原来的先后顺序
// loHead、loTail 对应一条链表,hiHead、hiTail 对应另一条链表,代码还是比较简单的
Node K,V loHead = null, loTail = null;
Node K,V hiHead = null, hiTail = null;
Node K,V next;
do {
next = e.next;
if ((e.hash oldCap) == 0) {
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
else {
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
} while ((e = next) != null);
if (loTail != null) {
loTail.next = null;
// 第一条链表
newTab[j] = loHead;
if (hiTail != null) {
hiTail.next = null;
// 第二条链表的新的位置是 j + oldCap,这个很好理解
newTab[j + oldCap] = hiHead;
return newTab;
# get 过程分析相对于 put 来说,get 真的太简单了。
计算 key 的 hash 值,根据 hash 值找到对应数组下标: hash (length-1)判断数组该位置处的元素是否刚好就是我们要找的,如果不是,走第三步判断该元素类型是否是 TreeNode,如果是,用红黑树的方法取数据,如果不是,走第四步遍历链表,直到找到相等(==或equals)的 key
public V get(Object key) {
Node K,V e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
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 // always check first node
((k = first.key) == key (key != null key.equals(k))))
return first;
if ((e = first.next) != null) {
// 判断是否是红黑树
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))))
return e;
} while ((e = e.next) != null);
return null;
# HashSet前面已经说过HashSet是对HashMap的简单包装,对HashSet的函数调用都会转换成合适的HashMap方法,因此HashSet的实现非常简单,只有不到300行代码。这里不再赘述。
//HashSet是对HashMap的简单包装
public class HashSet E
......
private transient HashMap E,Object map;//HashSet里面有一个HashMap
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
public HashSet() {
map = new HashMap ();
......
public boolean add(E e) {//简单的方法转换
return map.put(e, PRESENT)==null;
......
我要纠错 Collection - PriorityQueue源码解析 Map - LinkedHashSet Map源码解析
苏ICP备19053722号 pdai copyright © 2017-present Map - HashSet HashMap 源码解析 Java7 HashMap 概述 get() put() remove() Java8 HashMap put 过程分析 数组扩容 get 过程分析 HashSet 【双11】腾讯云服务器Java全栈读者专享
2核2G,4M,40GB, 50元/1年 查看2核4G,6M,60GB, 100元/1年 查看4核8G,10M,100GB, 300元/1年 查看目录Map - HashSet HashMap 源码解析 Java7 HashMap 概述 get() put() remove() Java8 HashMap put 过程分析 数组扩容 get 过程分析 HashSet 手机看微信扫一扫
可以手机看或分享至朋友圈
全屏看左栏交流圈添加pdai微信进《Java全栈知识体系》学习交流圈「无任何套路」 PS:添加时请备注Java全栈,谢谢! 下资料扫描公众号,回复“资料”下载10GB+书籍资料「无任何套路」公众号: Java全栈知识体系
支持我鼓励/支持/赞赏我
1. 不靠它生存但仍希望得到你的鼓励;
2. 时刻警醒自己保持技术人的初心,恒心,简单,利他;
(点击右侧❤️可以查看赞赏榜单和用途)
面试
上一篇
下一篇站点图 关于我 关于站点 最近更新记录问题反馈常用搜索百度 Google Bing Github 搜代码 技术社区CSDN OSChina 知否 掘金 Linux公社 IBM 开发者 StackOverflow Java相关面向对象基础语法基础集合框架并发基础并发关键字JUC并发框架IO框架Java8 特性JVM基础调试排错更多资源算法相关数组与线性表树详解图详解内部排序算法思想安全算法大数据处理分布式算法负载均衡算法推荐算法头脑风暴数据库相关数据库原理SQL语言MySQL相关MongoDBElasticSearch开发基础相关常用类库单元测试正则表达式网络协议安全相关常见重构技巧架构相关架构基础架构视角架构演进架构模式和要素高并发之缓存高并发之限流高并发之降级负载均衡容灾备份架构安全秒杀系统设计架构案例工具和部署工具集合IDE相关GitMavenLinuxDocker方法论SOLIDCAPBASE开源协议代码规范设计模式产品和团队产品相关团队相关其它分享
以上就是Map(map医学上)的详细内容,想要了解更多 Map的内容,请持续关注盛行IT软件开发工作室。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。