一、JDK 1.8 中 TreeSet 的 add 方法源码详细分析

TreeSet 是 Java 集合框架中的一个有序集合类,基于红黑树(TreeMap)实现。TreeSet 的 add 方法用于向集合中添加元素。如果元素已存在,则不会添加并返回 false;如果元素不存在,则添加并返回 true。下面我们将从 TreeSet 的 add 方法入手,逐步分析其源码实现

二、TreeSet 的 add 方法

TreeSet 的 add 方法源码如下:

参数说明

  • e:要添加的元素。

  • PRESENT:一个固定的 Object 对象,作为 TreeMap 的值(value)

返回值

  • 如果元素 e 不存在,map.put(e, PRESENT) 返回 null,表示添加成功

  • 如果元素 e 已存在,map.put(e, PRESENT) 返回 PRESENT,表示添加失败

三、TreeSet 的内部实现

TreeSet 的内部是基于 TreeMap 实现的。TreeSet 的元素作为 TreeMap 的键(key),而值(value)是一个固定的 PRESENT 对象(private static final Object PRESENT = new Object())

TreeSet 的构造函数

TreeSet 的构造函数会初始化内部的 TreeMap。例如:

PRESENT 对象

PRESENT 是一个静态常量,用于作为 TreeMap 的值:

四、TreeMap 的 put 方法

TreeSet 的 add 方法依赖于 TreeMap 的 put 方法。以下是 TreeMap 的 put 方法的源码(JDK 1.8):

    public V put(K key, V value) {
Entry<K,V> t = root; // 获取根节点
if (t == null) { // 如果树为空
compare(key, key); // 检查键是否为 null
root = new Entry<>(key, value, null); // 创建根节点
size = 1; // 大小设置为 1
modCount++; // 修改计数器加 1
return null; // 返回 null,表示添加成功
}
int cmp;
Entry<K,V> parent;
Comparator<? super K> cpr = comparator; // 获取比较器
if (cpr != null) { // 如果使用自定义比较器
do {
parent = t;
cmp = cpr.compare(key, t.key); // 比较键
if (cmp < 0) // 如果键小于当前节点
t = t.left; // 移动到左子树
else if (cmp > 0) // 如果键大于当前节点
t = t.right; // 移动到右子树
else // 如果键等于当前节点
return t.setValue(value); // 更新值并返回旧值
} while (t != null);
} else { // 如果使用自然顺序
if (key == null) // 如果键为 null
throw new NullPointerException(); // 抛出异常
Comparable<? super K> k = (Comparable<? super K>) key; // 强制转换为 Comparable
do {
parent = t;
cmp = k.compareTo(t.key); // 比较键
if (cmp < 0) // 如果键小于当前节点
t = t.left; // 移动到左子树
else if (cmp > 0) // 如果键大于当前节点
t = t.right; // 移动到右子树
else // 如果键等于当前节点
return t.setValue(value); // 更新值并返回旧值
} while (t != null);
}
Entry<K,V> e = new Entry<>(key, value, parent); // 创建新节点
if (cmp < 0) // 如果键小于父节点
parent.left = e; // 将新节点作为左子节点
else // 如果键大于父节点
parent.right = e; // 将新节点作为右子节点
fixAfterInsertion(e); // 修复红黑树的性质
size++; // 大小加 1
modCount++; // 修改计数器加 1
return null; // 返回 null,表示添加成功
}

五、源码解析

1、检查树是否为空:

  • 如果树为空,创建根节点并返回 null

2、比较键:

  • 如果使用自定义比较器,调用 compare 方法比较键

  • 如果使用自然顺序,调用 compareTo 方法比较键

3、查找插入位置:

  • 根据比较结果,移动到左子树或右子树

  • 如果找到相同的键,更新值并返回旧值

4、插入新节点:

  • 创建新节点,并根据比较结果将其作为左子节点或右子节点

5、修复红黑树的性质:

  • 调用 fixAfterInsertion 方法修复红黑树的性质(如颜色调整和旋转)

6、更新大小和修改计数器:

  • 大小加 1

  • 修改计数器加 1

六、总结

TreeSet 的 add 方法通过调用内部 TreeMap 的 put 方法实现元素的添加。它的核心逻辑是:

  • 如果元素不存在,添加到 TreeMap 中并返回 true

  • 如果元素已存在,返回 false

在 JDK 1.8 中,TreeMap 的实现基于红黑树,保证插入、删除和查找操作的时间复杂度为 O(log n)。TreeSet 的 add 方法适合需要有序集合的场景。在使用时,注意实现 Comparable 接口或提供 Comparator,并根据需求选择合适的集合类

TreeSet的add方法源码分析的更多相关文章

  1. TreeSet集合的add()方法源码解析(01.Integer自然排序)

    >TreeSet集合使用实例 >TreeSet集合的红黑树 存储与取出(图) >TreeSet的add()方法源码     TreeSet集合使用实例 package cn.itca ...

  2. Java split方法源码分析

    Java split方法源码分析 public String[] split(CharSequence input [, int limit]) { int index = 0; // 指针 bool ...

  3. invalidate和requestLayout方法源码分析

    invalidate方法源码分析 在之前分析View的绘制流程中,最后都有调用一个叫invalidate的方法,这个方法是啥玩意?我们来看一下View类中invalidate系列方法的源码(ViewG ...

  4. Linq分组操作之GroupBy,GroupJoin扩展方法源码分析

    Linq分组操作之GroupBy,GroupJoin扩展方法源码分析 一. GroupBy 解释: 根据指定的键选择器函数对序列中的元素进行分组,并且从每个组及其键中创建结果值. 查询表达式: var ...

  5. jQuery实现DOM加载方法源码分析

    传统的判断dom加载的方法 使用 dom0级 onload事件来进行触发所有浏览器都支持在最初是很流行的写法 我们都熟悉这种写法: window.onload=function(){ ... }  但 ...

  6. 【Java】NIO中Selector的select方法源码分析

    该篇博客的有些内容和在之前介绍过了,在这里再次涉及到的就不详细说了,如果有不理解请看[Java]NIO中Channel的注册源码分析, [Java]NIO中Selector的创建源码分析 Select ...

  7. jQuery.extend()方法和jQuery.fn.extend()方法源码分析

    这两个方法用的是相同的代码,一个用于给jQuery对象或者普通对象合并属性和方法一个是针对jQuery对象的实例,对于基本用法举几个例子: html代码如下: <!doctype html> ...

  8. jQuery.clean()方法源码分析(一)

    在jQuery 1.7.1中调用jQuery.clean()方法的地方有三处,第一次就是在我之前的随笔分析jQuery.buildFramgment()方法里面的,其实还是构造函数的一部分,在处理诸如 ...

  9. ArrayList方法源码分析

    本文将从ArrayList类的存储结构.初始化.增删数据.扩容处理以及元素迭代等几个方面,分析该类常用方法的源码. 数据存储设计 该类用一个Object类型的数组存储容器的元素.对于容量为空的情况,提 ...

  10. TreeSet与TreeMap的源码分析 JDK7

    TreeSet存储原则是:不可重复,有序的. public TreeSet() { this(new TreeMap<E,Object>()); } public TreeSet(Comp ...

随机推荐

  1. [学习笔记]最近公共祖先(LCA)之倍增算法

    1.定义 倍增法,顾名思义就是翻倍.它能够大大地优化时间复杂度.这个方法在很多算法中均有应用,例如求 LCA(最近公共祖先).(大雾) 2.框架 如下图,我们想找 \(4\) 和 \(8\) 的最近公 ...

  2. FIDO 密钥登录

    FIDO 密匙登录 [1]介绍了一些基础密码知识,科普性较好,在此摘抄一下: 说起密码,你会想起什么? 密码太多,记不住? 图省事所有网站用同一个密码,一个泄露了,手忙脚乱地去改密码? 网站被脱库,数 ...

  3. Win10 20H2 家庭版 环境变量

    20H2 家庭版设置环境变量,此电脑--->属性,弹出的是新版本的设置界面,选择左侧的"关于",在最右侧的"相关设置"里面,选择"高级系统设置& ...

  4. zos静态网站托管的使用和原理

    本文分享自天翼云开发者社区<zos静态网站托管的使用和原理> 作者:Ywq zos静态网站托管是一种功能强大且方便的功能特性,此特性主要用于将静态网站的文件(例如HTML.CSS.Java ...

  5. 通过virtual-install安装

    命令行 [root@kvm1 ~]# qemu-img create -f qcow2 centos6.10b.qcow2 10G Formatting 'vm1-disk1.qcow2', fmt= ...

  6. mac环境下配置jdk

    1.如果你是第一次配置环境变量,可以使用"touch .bash_profile" 创建一个.bash_profile的隐藏配置文件(如果你是为编辑已存在的配置文件,则使用&quo ...

  7. 打工人最强福音上线!AOne终端全面接入DeepSeek大模型!

    DeepSeek深度融合国产AI生态,国云连放大招! 继天翼云多款产品上线DeepSeek后, 见证企业级智能办公的时刻来了! 天翼云AOne联合国产大模型王者DeepSeek 带着671B满血版.7 ...

  8. LVGL 8.3.0常用函数快速使用

    LVGL 8.3.0使用快速上手教程(使用篇) 定义页面通用样式style // 创建页面样式 static lv_style_t style; lv_style_init(&style); ...

  9. Typecho如何去掉/隐藏index.php

    Typecho后台设置永久链接后,会在域名后加上index.php,很多人都接受不了.例如如下网址:https://www.jichun29.cn/index.php/archives/37/,但我们 ...

  10. Ansible - [08] 模块应用

    firewalld 模块 使用firewalld模块可以配置防火墙策略 [root@control ~]# cat ~/ansible/firewall.yml --- - hosts: agent ...