Java设计模式——适配器模式的精妙应用:探秘 JDK 源码中的 Set 类
在 Java 编程的世界里,JDK 源码犹如一座神秘的宝藏,其中的 Set 类更是我们日常开发中频繁使用的利器。今天,就让我们像勇敢的探险家一样,深入 JDK 源码,揭开 Set 类的神秘面纱,重点剖析适配器模式在其中的巧妙应用,看看它是如何让 Set 类焕发出独特魅力的!
一、Set 类:常用数据结构的重要角色
在我们的编程之旅中,Set 类就像一个收纳有序的工具箱,它具有不允许存储重复元素的特性,这使得它在处理数据去重、集合运算等场景中发挥着至关重要的作用。无论是处理用户输入数据、管理系统配置项,还是在复杂算法中进行数据筛选,Set 类都能助我们一臂之力。但你是否曾好奇,Set 类是如何在底层实现元素唯一性判断的呢?
二、适配器模式:Set 类背后的隐藏力量
(一)类图中的秘密
当我们审视 JDK 源码中与 Set 类相关的类图时,会惊喜地发现一个经典设计模式的身影——适配器模式。就像一位神奇的魔法师,它将 Map 接口的对象巧妙地包装成了 Set 接口,实现了两种不同接口之间的无缝转换。
(二)HashSet:适配器模式的实例展示
- 底层结构:依赖 HashMap
在 HashSet 的源码中,我们发现它内部持有一个 transient 的 HashMap 实例:
private transient HashMap<E,Object> map;
// 用于与 HashMap 中元素关联的虚拟值
private static final Object PRESENT = new Object();
这个 HashMap 就是实现 Set 功能的关键“幕后英雄”。HashSet 巧妙地利用了 HashMap 的特性来实现自己的功能。
2. 添加元素:委托给 HashMap
当我们调用 HashSet 的 add 方法时,实际上是将元素作为 HashMap 的键,而那个固定的 PRESENT 对象作为值,存入了 HashMap 中:
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
这样一来,通过 HashMap 键的唯一性,就轻松保证了 Set 中元素的唯一性。当我们向 HashSet 中添加元素时,就如同将物品放入一个经过特殊改造的 HashMap 容器中,它会自动帮我们去重。
3. 迭代器:获取 Map 的键迭代器
而当我们获取 HashSet 的迭代器时,它直接返回的是 HashMap 的键集合的迭代器:
public Iterator<E> iterator() {
return map.keySet().iterator();
}
这使得我们在遍历 HashSet 时,实际上是在遍历 HashMap 的键,从而获取到 Set 中的所有元素。
(三)LinkedHashSet:类似的适配逻辑
LinkedHashSet 的实现也别具匠心。它在构造函数中调用了父类的构造函数,最终创建了一个 LinkedHashMap:
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}
// 其他构造函数类似,最终都会调用到父类构造函数创建 LinkedHashMap
其构造函数最终会调用到类似这样的父类构造函数:
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
LinkedHashSet 利用 LinkedHashMap 的有序特性,不仅实现了元素的唯一性,还能保持元素插入的顺序,为我们提供了一种有序的 Set 实现。
(四)TreeSet:适配 NavigableMap
TreeSet 的实现同样依赖于适配器模式,它内部持有一个 transient 的 NavigableMap 实例:
private transient NavigableMap<E,Object> m;
private static final Object PRESENT = new Object();
TreeSet 通过将元素存储在 NavigableMap 中,并利用其排序功能,实现了对元素的有序存储和操作,为我们提供了一个有序且不重复的 Set 集合。
三、不仅仅是适配器模式:桥接模式的影子
有趣的是,在分析 JDK 源码中 Set 类的实现时,我们还能发现一些类似桥接模式的变形痕迹。虽然从本质上来说,这里的实现更符合适配器模式的定义,但这种相似性也让我们对设计模式的运用有了更深入的思考。它就像一座横跨在不同设计理念之间的桥梁,让我们看到了在实际编程中,设计模式之间可能存在的微妙联系和灵活转换。
四、总结与启示:源码学习的价值
通过深入剖析 JDK 源码中 Set 类对适配器模式的应用,我们不仅揭开了 Set 类高效实现元素唯一性判断和操作的神秘面纱,更深刻体会到了设计模式在优化代码结构、提高代码复用性和灵活性方面的巨大威力。这就像在黑暗中点亮了一盏明灯,为我们今后的编程实践指明了方向。
在日常编程中,我们不应仅仅满足于使用现成的类和接口,更应该像这样深入源码,学习大师们的设计思路和技巧。只有这样,我们才能不断提升自己的编程水平,打造出更加高效、健壮、优雅的软件系统。希望今天的探索能成为你编程之路上的宝贵财富,让我们一起在源码的海洋中继续畅游,发现更多的智慧结晶!
作者:代老师的编程课
出处:https://zthinker.com/
如果你喜欢本文,请长按二维码,关注 Java码界探秘
.
Java设计模式——适配器模式的精妙应用:探秘 JDK 源码中的 Set 类的更多相关文章
- 简单工厂(三)——JDK源码中的简单工厂
private static Calendar createCalendar(TimeZone zone,Locale aLocale) { CalendarProvider provider = L ...
- JDK源码中,都有哪些NB的设计模式?
转载:https://mp.weixin.qq.com/s/h88UxB9F2MkTbHqck3KQiQ 一.结构性模式: 1.适配器模式: 常用于将一个新接口适配旧接口 肥朝小声逼逼:在我们业务代码 ...
- Java1.8 JDK源码中,对两个类进行 按位与 操作是什么意思
Java容器类库中的Map接口(java\util\Map.java)中有一个Entry接口(java\util\Map.java),其中有几个接口方法用到了类和类的按位与操作,即类和类之间有 &am ...
- JDK源码中使用的设计模式
结构型模式: 适配器模式: 用来把一个接口转化成另一个接口. java.util.Arrays#asList() javax.swing.JTable(TableModel) java.io.Inpu ...
- JDK源码阅读:Object类阅读笔记
Object 1. @HotSpotIntrinsicCandidate @HotSpotIntrinsicCandidate public final native Class<?> g ...
- JDK源码中的英文注释翻译(Enum<E extends Enum<E>>)
public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializab ...
- JDK源码中的英文注释翻译(Class)
public final class Class<T> implements java.io.Serializable, GenericDeclaration, Type, Annotat ...
- JDK源码阅读:String类阅读笔记
String public final class String implements java.io.Serializable, Comparable<String>, CharSequ ...
- JDK源码那些事儿之浅析Thread上篇
JAVA中多线程的操作对于初学者而言是比较难理解的,其实联想到底层操作系统时我们可能会稍微明白些,对于程序而言最终都是硬件上运行二进制指令,然而,这些又太过底层,今天来看一下JAVA中的线程,浅析JD ...
- Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用
从网络上找的设计模式, 很全面,只要把UML类图看懂了, 照着类图将代码实现是很容易的事情. 步骤: 先看懂类图, 然后将代码实现, 之后再看文字 http://c.biancheng.net/des ...
随机推荐
- Asp.net core 学习笔记之异常处理
自己写代码自己维护, 你爱怎样写都可以, 确保一致性就可以了. 不要自己写,自己看不懂 /.\ 但是如果有一天你要别人也看得懂...那就不单单是一致性的问题了,最好是用大众的 style. refer ...
- Figma 学习笔记 – Comment
步骤 按 c 键 -> 点击区域 -> 写 comment -> post 它不仅仅在 design 的 page 可以写 comment 哦, 在预览 prototype 页面也是 ...
- Nuxt Kit 中的布局管理
title: Nuxt Kit 中的布局管理 date: 2024/9/18 updated: 2024/9/18 author: cmdragon excerpt: 摘要:本文详述了在Nuxt.js ...
- C4996 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS.
错误原因 VS平台认为scanf函数不安全,要求换成scanf_s函数 解决方案 方案一:将scanf换成scanf_s[不建议] 将scanf换成scanf_s 但是,scanf_s函数只能在vs上 ...
- Linux 循环设备 loop疑惑
什么是loop设备? loop设备是一种伪设备,是使用文件来模拟块设备的一种技术,文件模拟成块设备后, 就像一个磁盘或光盘一样使用.在使用之前,一个 loop 设备必须要和一个文件进行连接.这种结合方 ...
- 数据库故障处理优质文章汇总(含Oracle、MySQL、MogDB等)
数据库告警.紧急问题处理这些项目对于大多数朋友来讲应该不陌生了.从墨天轮社区整理的"最受DBA欢迎的技术文档合辑"系列中可以发现,大家对"故障诊断专题"的热情居 ...
- js 时间日期
Date.parse() 把字符串时间转化为时间戳. new Date(时间戳) 转化 时间格式 时间比较大小
- SaaS架构:中央库存系统架构设计
大家好,我是汤师爷~ 近年来,越来越多的零售企业大力发展全渠道业务.在销售额增长上,通过线上的小程序.直播.平台渠道等方式,拓展流量变现渠道.在会员增长方面,通过多样的互动方式,全渠道触达消费者,扩大 ...
- KubeSphere 社区双周报 | FluentBit 新增 tcp 输入插件 | 2023.09.29-10.12
KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书.新增的讲师证书以及两周内提交过 commit 的贡献者,并对近期重要的 PR 进行解析,同时还包含了线上/线下活动和布道推广等一系列 ...
- Kubernetes 集群中 Ingress 故障的根因诊断
作者:scwang18,主要负责技术架构,在容器云方向颇有研究. 前言 KubeSphere 是青云开源的基于 Kubernetes 的云原生分布式操作系统,提供了比较炫酷的 Kubernetes 集 ...