在 Java 编程的世界里,JDK 源码犹如一座神秘的宝藏,其中的 Set 类更是我们日常开发中频繁使用的利器。今天,就让我们像勇敢的探险家一样,深入 JDK 源码,揭开 Set 类的神秘面纱,重点剖析适配器模式在其中的巧妙应用,看看它是如何让 Set 类焕发出独特魅力的!

一、Set 类:常用数据结构的重要角色

在我们的编程之旅中,Set 类就像一个收纳有序的工具箱,它具有不允许存储重复元素的特性,这使得它在处理数据去重、集合运算等场景中发挥着至关重要的作用。无论是处理用户输入数据、管理系统配置项,还是在复杂算法中进行数据筛选,Set 类都能助我们一臂之力。但你是否曾好奇,Set 类是如何在底层实现元素唯一性判断的呢?

二、适配器模式:Set 类背后的隐藏力量

(一)类图中的秘密

当我们审视 JDK 源码中与 Set 类相关的类图时,会惊喜地发现一个经典设计模式的身影——适配器模式。就像一位神奇的魔法师,它将 Map 接口的对象巧妙地包装成了 Set 接口,实现了两种不同接口之间的无缝转换。

(二)HashSet:适配器模式的实例展示

  1. 底层结构:依赖 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 类的更多相关文章

  1. 简单工厂(三)——JDK源码中的简单工厂

    private static Calendar createCalendar(TimeZone zone,Locale aLocale) { CalendarProvider provider = L ...

  2. JDK源码中,都有哪些NB的设计模式?

    转载:https://mp.weixin.qq.com/s/h88UxB9F2MkTbHqck3KQiQ 一.结构性模式: 1.适配器模式: 常用于将一个新接口适配旧接口 肥朝小声逼逼:在我们业务代码 ...

  3. Java1.8 JDK源码中,对两个类进行 按位与 操作是什么意思

    Java容器类库中的Map接口(java\util\Map.java)中有一个Entry接口(java\util\Map.java),其中有几个接口方法用到了类和类的按位与操作,即类和类之间有 &am ...

  4. JDK源码中使用的设计模式

    结构型模式: 适配器模式: 用来把一个接口转化成另一个接口. java.util.Arrays#asList() javax.swing.JTable(TableModel) java.io.Inpu ...

  5. JDK源码阅读:Object类阅读笔记

    Object 1. @HotSpotIntrinsicCandidate @HotSpotIntrinsicCandidate public final native Class<?> g ...

  6. JDK源码中的英文注释翻译(Enum<E extends Enum<E>>)

    public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializab ...

  7. JDK源码中的英文注释翻译(Class)

    public final class Class<T> implements java.io.Serializable, GenericDeclaration, Type, Annotat ...

  8. JDK源码阅读:String类阅读笔记

    String public final class String implements java.io.Serializable, Comparable<String>, CharSequ ...

  9. JDK源码那些事儿之浅析Thread上篇

    JAVA中多线程的操作对于初学者而言是比较难理解的,其实联想到底层操作系统时我们可能会稍微明白些,对于程序而言最终都是硬件上运行二进制指令,然而,这些又太过底层,今天来看一下JAVA中的线程,浅析JD ...

  10. Java设计模式:23种设计模式全面解析(超级详细)以及在源码中的应用

    从网络上找的设计模式, 很全面,只要把UML类图看懂了, 照着类图将代码实现是很容易的事情. 步骤: 先看懂类图, 然后将代码实现, 之后再看文字 http://c.biancheng.net/des ...

随机推荐

  1. JavaScript Library – Alpine.js

    前言 Alpine 是高山的意思.Alpine.js 是一个轻量级的 JS Framework. 我为什么会去用它呢? 是这样的,我在做企业网站开发的时候会有 2 个阶段. 第一个 draft 阶段, ...

  2. Figma 学习笔记 – Team Library Style and Component

    Design System 我们做设计通常会 Follow 一个 Design System, 比如 Material Guide. 里头会定义 Font, Color, Effect (Elevat ...

  3. [OI] 偏序

    \(n\) 维偏序即给出若干个点对 \((a_{i},b_{i},\cdots,n_{i})\),对每个 \(i\) 求出满足 \(a_{j}\gt a_{i},b_{j}\gt b_{i}\cdot ...

  4. 暑假集训CSP提高模拟2

    A.活动投票 主元素问题,用摩尔投票 #include<bits/stdc++.h> using namespace std; int n,a=-1,acnt,x; int main(){ ...

  5. PHP提薪模块

    在使用es搜索的时候需要注意以下这几点 文档(Document)与索引(Index):在ES中,文档是最小的数据单元,类似于数据库中的一行记录.文档组织在索引中,索引类似于数据库中的表.了解如何创建索 ...

  6. 深入理解Linux进程调度(下)

    一.SMP管理 在继续讲解之前,我们先来说一下多CPU管理(这里的CPU是指逻辑CPU,在很多语境中CPU都是默认指的逻辑CPU,物理CPU要特别强调是物理CPU).最开始的时候计算机都是单CPU的, ...

  7. Lazy TLB Mode 的工作原理

    Lazy TLB (Translation Lookaside Buffer) mode 是操作系统和处理器在管理虚拟内存时的一种优化技术,旨在提高处理器的性能.要理解 Lazy TLB mode,需 ...

  8. EAS(能量感知调度)绿色节能调度器

    能量感知调度(EAS)使调度程序能够预测其决策对 CPU 消耗的电量的影响. EAS 依赖于 CPU 的能量模型 (EM) 来为每个任务选择省电的 CPU,同时要求对执行任务的吞吐量的影响最小. EA ...

  9. 2021年1月国产数据库排行榜:OceanBase重回前三,TDSQL增长趋势最强劲!

    墨天轮国产数据库排行榜新年第一期已发布.2021年1月份排行榜前三甲依次为 TiDB .DaMeng.OceanBase .PingCAP TiDB 稳居冠军的宝座,短时间内难以撼动,开源的商业数据库 ...

  10. 权限控制 vue3