java TreeSet 和 TreeMap 源码解读

2023-11-01

目录

一、前言

二、TreeSet详解

        1.TreeSet简介

        2.TreeSet的底层实现

                0° 准备工作

                1° TreeSet构造器

                2° 匿名内部类实现接口的多态

                3° TreeMap构造器

                4° add方法

                5° put方法和put方法

                6° 继续添加元素 

                7° 修改比较器的比较原则

        3.TreeSet去重机制 : 

三、TreeMap详解

        1.TreeMap简介

        2.TreeMap的底层实现

                0° 准备工作

                1° TreeMap构造器              

                2° add方法。

                3° 外层put和内层put

                4° 向集合添加第二个元素

                5° 改变判断元素的条件

四、完结撒❀


一、前言

        大家好,本篇博文将通过Debug流程分析,带大家仔细剖析一下TreeSet以及TreeMap的底层实现。TreeSet的底层其实就是TreeMap,见名知意,与树有关,鉴于二者的底层都涉及到了较多数据结构的内容,目前在过渡阶段,up就“详略得当”(bushi),给大家把重点内容过一下就行,当然还是比一般地方讲得要细的。
        注意 : 解读源码需要扎实的基础,比较适合希望深究的同学; 不要眼高手低,看会了不代表你会了,自己动手跟着过一遍才算有收获; 点击文章的侧边栏目录或者前面的目录可以进行跳转。 良工不示人以朴,up所有文章都会适时进行补充完善。大家有问题都可以在评论区讨论交流,或者私信up。 感谢阅读!


二、TreeSet详解

        1.TreeSet简介

                TreeSet是Set接口的一个实现类,其类图如下 :

                TreeSet中的元素不能为null,否则会报NullPointerException。                
                与HashSet实现类不同,TreeSet最大的特点是可以进行排序。TreeSet底层是二叉树,可以对对象元素进行排序,但是自定义类需要实现comparator接口,可以使用匿名内部类实现该接口,并在匿名内部类中重写compare方法。

        2.TreeSet的底层实现

                0° 准备工作

                为了通过Debug,结合源码来分析TreeSet的底层,up以TreeSet_Demo类为演示类,代码如下 : (main函数第一行设置断点)

package csdn.knowledge.api_tools.gather.set;

import java.util.Comparator;
import java.util.TreeSet;

/**
 * @author : Cyan_RA9
 * @version : 21.0
 */
public class TreeSet_Demo {
    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o1).compareTo((String)o2);
            }
        });

        treeSet.add("141");
        treeSet.add("5");
        treeSet.add("23");
        treeSet.add("114514");

        System.out.println("treeSet = " + treeSet);
    }
}

                1° TreeSet构造器

                进入Debug界面,首先我们跳入TreeSet的带参构造,如下

                可以看到,TreeSet底层的确调用了TreeMap。我们先不急着跳入TreeMap的构造器,先来看看TreeSet带参构造的形参——一个Comparator(比较器)类型的变量,这个Comparator类型其实就是一个接口其源码如下

                2° 匿名内部类实现接口的多态

                而我们一开始传入的这个玩意儿——

        new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o1).compareTo((String)o2);
            }
        }

                其实就是一个实现了该接口的匿名内部类对象,并在TreeSet带参构造中形成了多态。而在TreeSet带参构造中,又将匿名内部类对象comparator传递给了TreeMap的一个带参构造。
                匿名内部类中实现了Comparator()接口中的compare方法,该方法决定了TreeSet集合中元素排序的原则。此时,排序的规则是由String类的compareTo方法决定的,我们来简单回顾一下String类的compareTo方法如下——

        int compareTo(String anotherString)——

        返回两个字符串对象的比较结果——若相等,返回0;若不相等,从两个字符串的第一个字符开始比较,返回第一个不相等的字符的ASCII码差值。当较长字符串的前面部分恰巧是较短的字符串时,返回两个字符串的长度差。

                因此,根据此规则,当前TreeSet集合中的元素应该是按字母表顺序来排列的,比方说我现在传入了两个字符串o1和o2,分别为"ABC"和"BBC",那么此时compareTo方法的返回值就是A的ASCII码值 - B的ASCII码值 = 65 - 66 = -1,而-1是小于0的;那么在使用add方法添加元素时,compareTo方法的这个返回值就决定了添加元素时的排列顺序,关于这一点,在下面的add方法中可以体现。

                3° TreeMap构造器

                好的,我们接下来再追入TreeMap的带参构造看看,如下图所示 : 

                可以看到,在TreeMap构造器中,又将匿名内部类对象comparator传递给了TreeMap的一个属性comparator
                并且,此时的comparator已经显示为了匿名内部类“TreeSet_Demo$1”的形式。
                接下里我们跳出构造器,逐层返回到演示了中。

                4° add方法

                像TreeSet集合中添加第一个元素"141",跳入add方法,如下所示 : 

                可以看到,底层仍然走的是put方法;注意实参中的PRESENT, 这个PRESENT就和HashSet中PRESENT是一个作用了,仅仅是作为一个空对象,起到占位的作用,其源码如下 : 

                5° put方法和put方法

                继续跳入put方法,如下所示 : 

                经典的“包皮”结构, 继续跳入内层put方法,如下 : 

                内层的put方法代码是非常多并且复杂的,里面涉及到许多数据结构的知识。还好,这是第一次添加元素,直接进入第一个if语句就return出去了

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java TreeSet 和 TreeMap 源码解读 的相关文章

  • 如何使用固定数量的工作线程实现简单线程

    我正在寻找最简单 最直接的方法来实现以下内容 主程序实例化worker 执行任务的线程 Only n任务可以同时运行 When n已达到 不再有工人 开始直到计数 正在运行的线程回落到下方n 我觉得Executors newFixedThr
  • 在Java中将*s打印为三角形?

    我在 Java 课程中的作业是制作 3 个三角形 一份左对齐 一份右对齐 一份居中 我必须为什么类型的三角形制作一个菜单 然后输入需要多少行 三角形必须看起来像这样 到目前为止 我能够完成左对齐的三角形 但我似乎无法获得其他两个 我尝试用谷
  • ScheduledThreadPoolExecutor如何在特定时间运行任务?

    特别是 它是否像这样在内部实现了 while true 循环 while System currentTimeMillis lt timeToRunTask Thread sleep 1000 doTask From http grepco
  • 如何将 JSpinner 的值设置为特定日期

    我有一个JSpinner我添加到JPanel我想将其时间设置为 GregorianCalendar calendar JSpinner spinner new JSpinner spinner setModel model pom add
  • Quarkus 不以编程方式选择 bean

    我试图以编程方式选择 bean 但 quarkus 不会注入 bean 并引发异常 不支持吗 public enum ReportType ONE TWO Qualifier Retention RUNTIME Target METHOD
  • 如何提取文件 jre-9/lib/modules?

    In JRE 9 lib目录 至少在 Windows 上 有一个名为modules其大小约为107 MB 是否可以提取该文件或在其中列出 java 模块 我可以看到一个名为jmod可以在jdk 9 bin jmod exe 但那是为了阅读
  • 在命令行java中突出显示文本[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有一项任务是重新创建 unix cal 程序 除了一部分之外 相当简单 今天 它突出显示了该数字 我不知道该怎么做 关于如何在 Ja
  • 项目缺少所需的注释处理库

    我的 Eclipse IDE 突然在问题视图中显示 xxxx 项目缺少所需的注释处理库 xxxx M2 REPO 中的一些旧 jar 我用谷歌搜索 没有找到任何答案 为什么我的项目使用旧的 jar 以及错误来自哪里 To remove th
  • javax.persistence.RollbackException:提交事务时出错],根本原因是 java.lang.StackOverflowError:null

    我有一个使用 Spring Data REST 框架的 Spring Boot API 从 spring boot starter parent 2 1 0 RELEASE 继承的依赖项 我正在尝试执行 PUT 或 PATCH 请求来更新实
  • 当 JMS Prod 位于辅助 POJO 类中时,如何在事务中包含 JMS Producer

    简短的问题 有没有办法强制无状态 EJB 调用的 POJO 存在于 EJB 的上下文中 以便事务和资源注入可以在 POJO 中工作 具体来说 在我想要做的事情的上下文中 如何在 EJB 的事务中包含 POJO JMS 生产者 该生产者在调用
  • Android volley使用RequestFuture.get()时出现超时异常

    在我的片段中 我尝试使用 TMDB 的开放电影数据库来获取有关 正在播放 电影的详细信息 如果我使用 RequestFuture get time TimeUnit 方法来执行此齐射请求 我总是会收到超时错误 如果我在 Safari 中手动
  • Java - JPanel 内有边距和 JTextArea

    我想创建这样的东西 主面板有其边距 x 并且 TextArea 位于该面板的中心 几乎填满了面板 底部是另一个具有自定义尺寸 高度 y 的面板 可以使用某些快捷方式将其切换为可见和不可见 底部面板有 FlowLayout 和几个元素 问题是
  • 将现有 eclipse 项目导出到 war 文件时出现“模块名称无效”

    我正在尝试将现有 Eclipse 项目导出到 war 文件 但无论我在 WAR Export 对话框页面中输入什么 系统总是返回 模块名称无效 我不知道如何解决这个问题 谢谢您的帮助 我有同样的问题 我修复了它 请按照以下步骤操作 您可以创
  • Android 解析 JSON 卡在 get 任务上

    我正在尝试解析一些 JSON 数据 我的代码工作了一段时间 我不确定我改变了什么突然破坏了代码 当我运行代码时 我没有收到任何运行时错误或警告 我创建一个新的 AsyncTask 并执行它 当我打电话时 get 在这个新任务中 调试器在此行
  • 如何检查日期字符串的有效性?

    在我的项目中 我需要检查日期字符串是否计算为正确的日期对象 我决定允许 yyyy MM dd 和日期格式 年 月 日 和 年 月 日 小时 分钟 我如何检查它们是否有效 我的代码为 1980 01 01 和一些奇怪的日期 如 3837 05
  • 从浏览器访问本地文件?

    您好 我想从浏览器访问系统的本地文件 由于涉及大量安全检查 是否可以通过某种方式实现这一目标 或使用 ActiveX 或 Java Applet 的任何其他工作环境 请帮帮我 要通过浏览器访问本地文件 您可以使用签名的 Java Apple
  • Java String ReplaceAll 方法给出非法重复错误?

    我有一个字符串 当我尝试运行时replaceAll方法 我收到这个奇怪的错误 String str something op str str replaceAll o n it works fine str str replaceAll n
  • JPA 将 BigDecimal 作为整数保存在数据库中

    我在数据库中有这个字段 ITEMCOST NUMERIC 13 DEFAULT 0 NOT NULL 在JAVA中 Entity中的字段定义如下 Column name ITEMCOST private BigDecimal itemCos
  • 传递 Android DialogFragment 参数时,onCreateDialog 捆绑参数意外为 null

    我正在尝试使用 DialogFragment 在 Android 中显示一个基本对话框 并使用对话框消息的参数 如中所述StackOverflow线程 https stackoverflow com questions 15459209 p
  • 如何使用 Jest 从 ElasticSearch 获取索引列表

    我正在尝试使用 Jest 检索索引列表 但我只得到 Stats statistics new Stats Builder build result client execute statistics 如何从结果中检索索引列表 除了统计之外

随机推荐

  • VL53L0X调试总结

    最近调VL53L0X花了不少时间 特总结下 https www st com content st com en search html q vl53l t products page 1 VL53L0X测距2m VL53L1X测距4m 支
  • networkx 中文学习手册

    文章目录 创建图表 节点 边 检查图的元素 从图中删除元素 使用图构造函数 什么用作节点和边 访问边和邻居 向图 节点和边添加属性 图形属性 节点属性 边缘属性 多图 图生成器和图操作 1 应用经典的图操作 例如 2 使用对经典小图之一的调
  • Harmony OS WiFi编程——连接热点、创建热点

    本节主要介绍如何在HiSpark WiFi IoT套件上使用Hamony OS的WiFi相关编程接口 相关知识点 WiFi的工作模式 AP模式 热点模式 提供无线接入服务 允许其它无线设备接入 提供数据访问 一般的无线路由 网桥工作在该模式
  • JavaNote 1.7final、finally、访问权限

    一 final 1 final的变量的值不能被改变 2 final的方法不能被重写 3 final的类不能被继承 二 finally finally 语句块 必须执行 通常在finally语句块中执行资源清除工作 如关闭打开的文件 删除临时
  • 基于Sklearn实现LDA算法

    文章目录 一 LDA算法 二 sklearn实现LDA 三 结果如图 四 总结 五 参考 一 LDA算法 1 线性判别分析 Linear Discriminant Analysis LDA 方法常被用于数据预处理中的降维 dimension
  • ArcMap布局视图的图例设置,如显示符号、标注、描述等

    转载请注明作者 独孤尚良dugushangliang 出处 https blog csdn net dugushangliang article details 81305762 如上图所示 为了达到以上的图例显示效果 鄙人上下求索 废了不
  • vue动态生成二维码,扫码登录

    首先找到对应的的三个接口 1 二维码获取key接口 接口说明 调用此接口可生成一个key 2 二维码生成接口 接口说明 调用此接口传入上一个接口生成的key可生成二维码图片的base64和二维码信息 可使用base64展示图片 或者使用二维
  • mysql自动启动设置用Systemctl start mysqld启动

    1 如果你是用yum安装的话就不需要进行设置了 用systemctl restart mysqld启动报如下错 2 查看系统服务有没有mysqld chkconfig list 3 MySQL启动关闭添加到 etc init d mysql
  • 解决Chrome浏览器中部分字体显示模糊的问题

    如果在Chrome浏览器中查看某些网页时 发现大部分字体显示清晰 但是另外部分字体显示模糊看不清的话 有可能是浏览器字体设置的问题 解决方式如下 1 点击Chrome浏览器右上角的 按钮 点击 设置 菜单 或直接在地址栏中输入 chrome
  • 解决java.net.BindException: Address already in use(Bind failed)端口占用问题

    sudo lsof i 8080 删掉图中两个进程 kill 9 2960 其中 9是九
  • 分别采用prim算法与kruskal算法构造最小生成树(第一次作业)

    分别采用prim算法与kruskal算法构造最小生成树 1 问题 举一个实例 画出采用Prim算法构造最小生成树的过程 并按实验报告模板编写算法 举一个实例 画出采用Kruskal算法构造最小生成树的过程 并按实验报告模板编写算法 有n个村
  • axios get请求特殊字符编码问题

    这几天在写一个项目 然后就遇到了请求的编码问题 然后在度娘上搜到了答案 请求拦截器配置处理 this axiosInstance interceptors request use config AxiosRequestConfig gt c
  • go换源国内并根据mod文件下载依赖

    go env w GO111MODULE on go env w GOPROXY https goproxy cn direct 根据mod文件下载依赖 此命令需要在go mod同级目录下执行 go mod tidy
  • 做EEG频谱分析,看这一篇文章就够了!

    所谓频谱分析 又称为功率谱分析或者功率谱密度 Power Spectral Density PSD 分析 实际就是通过一定方法求解信号的功率power随着频率变化曲线 笔者在这里对目前常用的频谱分析方法做一个总结 并重点介绍目前EEG分析中
  • Outlook Express 无法连接服务器,错误号:0x800CCC0E

    发送邮件的时候报错 无法发送邮件 显示无法连接到服务器 邮箱为公司外部邮箱 协议 SMTP 端口 25 套接字错误 10060 错误号 0x800CCC0E 含义是 无法连接服务器 请确定一下是否可以正常连接SMTP服务器 一般解决方法是
  • HTTP断点续传原理 状态码206 Partial Content

    HTTP断点续传 断点续传就是从文件上次中断的地方开始重新下载或上传 当下载或上传文件的时候 如果没有实现断点续传功能 那么每次出现异常或者用户主动的暂停 都会去重头下载 这样很浪费时间 所以断点续传的功能就应运而生了 要实现断点续传的功能
  • DVWA全级别通关教程

    首先选择难度 我们从low开始 如上图所示进行修改 目录 SQL手工注入 过程 low Medium high Impossible SQL 盲注 过程 SQL 工具注入 工具安装过程 过程 low Medium High 暴力破解 过程
  • 基于SSM的校园学生管理系统的设计与实现

    全网粉丝20W csdn特邀作者 博客专家 CSDN新星计划导师 java领域优质创作者 博客之星 掘金 华为云 阿里云 InfoQ等平台优质作者 专注于Java技术领域和毕业项目实战 文末获取项目下载方式 一 项目背景介绍 校园学生管理系
  • pc 电商平台----search模块

    目录 vuex中的模块化 Object assign 用法 watch监听 数组方法splice与split splice split 方法 数组去重 自定义分页器 vuex中的模块化 vuex使用三部曲 写请求 页面dispatch派发a
  • java TreeSet 和 TreeMap 源码解读

    目录 一 前言 二 TreeSet详解 1 TreeSet简介 2 TreeSet的底层实现 0 准备工作 1 TreeSet构造器 2 匿名内部类实现接口的多态 3 TreeMap构造器 4 add方法 5 put方法和put方法 6 继