精尽 JDK 源码解析 —— 集合(七)TreeSet
1. 概述
TreeSet ,基于 TreeSet 的 Set 实现类。在业务中,如果我们有排重+ 排序的需求,一般会考虑使用 TreeSet 。不过,貌似很少会出现排重+ 排序的双重需求。
2. 类图
TreeSet 实现的接口、继承的类,如下图所示:正在上传…重新上传取消类图
- 实现 java.util.NavigableSet 接口,并继承 java.util.AbstractSet 抽像类。
- 实现 java.io.Serializable 接口。
- 实现 java.lang.Cloneable 接口。
对于 NavigableSet 和 SortedMap 接口,已经添加注释,直接点击查看。
3. 属性
TreeSet 只有一个属性,那就是 m
。代码如下:
// TreeSet.javaprivate transient NavigableMap<E,Object> m; |
m
的 key ,存储 HashSet 的每个 key 。map
的 value ,因为 TreeSet 没有 value 的需要,所以使用一个统一的PRESENT
即可。代码如下:// TreeSet.java// Dummy value to associate with an Object in the backing Map private static final Object PRESENT = new Object();
4. 构造方法
TreeSet 一共有 5 个构造方法,代码如下:
// TreeSet.javaTreeSet(NavigableMap<E,Object> m) {this.m = m; }public TreeSet() {this(new TreeMap<>()); }public TreeSet(Comparator<? super E> comparator) {this(new TreeMap<>(comparator)); }public TreeSet(Collection<? extends E> c) {this();// 批量添加addAll(c); }public TreeSet(SortedSet<E> s) {this(s.comparator());// 批量添加addAll(s); } |
- 在构造方法中,会创建 TreeMap 对象,赋予到
m
属性。
5. 添加单个元素
#add(E e)
方法,添加单个元素。代码如下:
// TreeSet.javapublic boolean add(E e) {return m.put(e, PRESENT)==null; } |
m
的 value 值,就是我们看到的PRESENT
。
#addAll(Collection<? extends E> c)
方法,批量添加。代码如下:
// TreeSet.javapublic boolean addAll(Collection<? extends E> c) {// Use linear-time version if applicable// 情况一if (m.size()==0 && c.size() > 0 &&c instanceof SortedSet &&m instanceof TreeMap) {SortedSet<? extends E> set = (SortedSet<? extends E>) c;TreeMap<E,Object> map = (TreeMap<E, Object>) m;if (Objects.equals(set.comparator(), map.comparator())) {map.addAllForTreeSet(set, PRESENT);return true;}}// 情况二return super.addAll(c); } |
- 在实现上,和 TreeMap 的批量添加是一样的,对于情况一,会进行优化。
6. 移除单个元素
#remove(Object o)
方法,移除 o
对应的 value ,并返回是否成功。代码如下:
// TreeSet.javapublic boolean remove(Object o) {return m.remove(o)==PRESENT; } |
7. 查找单个元素
#contains(Object key)
方法,判断 key 是否存在。代码如下:
// TreeSet.javapublic boolean contains(Object o) {return m.containsKey(o); } |
8. 查找接近的元素
在 NavigableSet 中,定义了四个查找接近的元素:
#lower(E e)
方法,小于e
的 key#floor(E e)
方法,小于等于e
的 key#higher(E e)
方法,大于e
的 key#ceiling(E e)
方法,大于等于e
的 key
我们一起来看看哈。
// TreeSet.javapublic E lower(E e) {return m.lowerKey(e); }public E floor(E e) {return m.floorKey(e); }public E ceiling(E e) {return m.ceilingKey(e); }public E higher(E e) {return m.higherKey(e); } |
9. 获得首尾的元素
#first()
方法,获得首个 key 。代码如下:
// TreeSet.javapublic E first() {return m.firstKey(); } |
#pollFirst()
方法,获得并移除首个 key 。代码如下:// TreeSet.javapublic E pollFirst() {Map.Entry<E,?> e = m.pollFirstEntry();return (e == null) ? null : e.getKey(); }
#last()
方法,获得尾部 key 。代码如下:
// TreeSet.javapublic E last() {return m.lastKey(); } |
#pollLast()
方法,获得并移除尾部 key 。代码如下:// TreeSet.javapublic E pollLast() {Map.Entry<E,?> e = m.pollLastEntry();return (e == null) ? null : e.getKey(); }
10. 清空
#clear()
方法,清空。代码如下:
// TreeSet.javapublic void clear() {m.clear(); } |
11. 克隆
#clone()
方法,克隆 TreeSet 。代码如下:
// TreeSet.javapublic Object clone() {// 克隆创建 TreeSet 对象TreeSet<E> clone;try {clone = (TreeSet<E>) super.clone();} catch (CloneNotSupportedException e) {throw new InternalError(e);}// 创建 TreeMap 对象,赋值给 clone 的 m 属性clone.m = new TreeMap<>(m);return clone; } |
12. 序列化
#writeObject(ObjectOutputStream s)
方法,序列化 TreeSet 对象。代码如下:
// TreeSet.java@java.io.Serial private void writeObject(java.io.ObjectOutputStream s)throws java.io.IOException {// Write out any hidden stuff// 写入非静态属性、非 transient 属性s.defaultWriteObject();// Write out Comparator// 写入比较器s.writeObject(m.comparator());// Write out size// 写入 key-value 键值对数量s.writeInt(m.size());// Write out all elements in the proper order.// 写入具体的 key-value 键值对for (E e : m.keySet())s.writeObject(e); } |
13. 反序列化
#readObject(ObjectInputStream s)
方法,反序列化成 TreeSet 对象。代码如下:
// TreeSet.java@java.io.Serial private void readObject(java.io.ObjectInputStream s)throws java.io.IOException, ClassNotFoundException {// Read in any hidden stuff// 读取非静态属性、非 transient 属性s.defaultReadObject();// Read in Comparator// 读取比较器@SuppressWarnings("unchecked")Comparator<? super E> c = (Comparator<? super E>) s.readObject();// Create backing TreeMap// 创建 TreeMap 对象TreeMap<E,Object> tm = new TreeMap<>(c);m = tm;// Read in size// 读取 key-value 键值对数量int size = s.readInt();// 读取具体的 key-value 键值对tm.readTreeSet(size, s, PRESENT); }// TreeMap.javavoid readTreeSet(int size, java.io.ObjectInputStream s, V defaultVal)throws java.io.IOException, ClassNotFoundException {buildFromSorted(size, null, s, defaultVal); } |
14. 获得迭代器
// TreeSet.javapublic Iterator<E> iterator() { // 正序 Iterator 迭代器return m.navigableKeySet().iterator(); }public Iterator<E> descendingIterator() { // 倒序 Iterator 迭代器return m.descendingKeySet().iterator(); } |
15. 转换成 Set/Collection
// TreeSet.javapublic NavigableSet<E> descendingSet() {return new TreeSet<>(m.descendingMap()); } |
16. 查找范围的元素
// TreeSet.java// subSet 组 public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,E toElement, boolean toInclusive) {return new TreeSet<>(m.subMap(fromElement, fromInclusive,toElement, toInclusive)); } public SortedSet<E> subSet(E fromElement, E toElement) {return subSet(fromElement, true, toElement, false); }// headSet 组 public NavigableSet<E> headSet(E toElement, boolean inclusive) {return new TreeSet<>(m.headMap(toElement, inclusive)); } public SortedSet<E> headSet(E toElement) {return headSet(toElement, false); }// tailSet 组 public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {return new TreeSet<>(m.tailMap(fromElement, inclusive)); }public SortedSet<E> tailSet(E fromElement) {return tailSet(fromElement, true); } |
精尽 JDK 源码解析 —— 集合(七)TreeSet相关推荐
- 精尽 JDK 源码解析 —— 集合(五)哈希集合 HashSet
1. 概述 HashSet ,基于 HashMap 的 Set 实现类.在业务中,如果我们有排重的需求,一般会考虑使用 HashSet . 在 Redis 提供的 Set 数据结构,不考虑编码的情况下 ...
- 精尽 JDK 源码解析 —— 集合(二)链表 LinkedList
1. 概述 LinkedList ,基于节点实现的双向链表的 List ,每个节点都指向前一个和后一个节点从而形成链表. 相比 ArrayList 来说,我们日常开发使用 LinkedList 相对比 ...
- 精尽 JDK 源码解析 —— 集合(四)哈希表 LinkedHashMap
1. 概述 众所周知,HashMap 提供的访问,是无序的.而在一些业务场景下,我们希望能够提供有序访问的 HashMap .那么此时,我们就有两种选择: TreeMap :按照 key 的顺序. L ...
- JDK源码解析 迭代器模式在JAVA的很多集合类中被广泛应用,接下来看看JAVA源码中是如何使用迭代器模式的。
JDK源码解析 迭代器模式在JAVA的很多集合类中被广泛应用,接下来看看JAVA源码中是如何使用迭代器模式的. 看完这段代码是不是很熟悉,与我们上面代码基本类似.单列集合都使用到了迭代器,我们以Arr ...
- snabbdom源码解析(七) 事件处理
事件处理 我们在使用 vue 的时候,相信你一定也会对事件的处理比较感兴趣. 我们通过 @click 的时候,到底是发生了什么呢! 虽然我们用 @click绑定在模板上,不过事件严格绑定在 vnode ...
- JDK源码解析 Comparator 中的策略模式
JDK源码解析 Comparator 中的策略模式.在Arrays类中有一个 sort() 方法,如下: public class Arrays{public static <T> voi ...
- JDK源码解析 Runable是一个典型命令模式,Runnable担当命令的角色,Thread充当的是调用者,start方法就是其执行方法
JDK源码解析 Runnable是一个典型命令模式, Runnable担当命令的角色,Thread充当的是调用者,start方法就是其执行方法 /命令接口(抽象命令角色) public interfa ...
- JDK源码解析 InputStream类就使用了模板方法模式
JDK源码解析 InputStream类就使用了模板方法模式. 在InputStream类中定义了多个 read() 方法,如下: public abstract class InputStream ...
- JDK源码解析 Integer类使用了享元模式
JDK源码解析 Integer类使用了享元模式. 我们先看下面的例子: public class Demo {public static void main(String[] args) {Integ ...
最新文章
- CentOS 6.4下PXE+Kickstart无人值守安装操作系统
- java安装好了打不开机_这都不犯规?王骁辉尺度把握得真好 难怪0+0+0能打20分钟...
- AndroidStudio设置背景颜色,字体大小,默认显示行号
- javaweb学习总结二十三(servlet开发之线程安全问题)
- 光流 | OpenCV实现简单的optical flow(代码类)
- linux安装磁盘分区设置,Linux安装与磁盘分区.doc
- 面经系列 | Python,数据结构,神经网络
- Matlab矩阵、元胞数组的合并拼接
- django无法生成自定义表(mysql)
- Flutter AnimatedSwitcher 实现优美的图片切换动画
- 弯道超车时机已来 百度:中国有机会定义AI时代的用户体验标准
- 【MYSQL快速入门】常用函数:日期函数
- 滞后问题_富锂正极材料的电压滞后问题
- bjui获取当前页签或者是dialog容器
- 内部推荐岗位信息201508
- 查看服务器sftp用户信息,linux查看sftp服务器配置
- Round14—最小生成树
- 如何使用Python提取pdf表格及文本,并保存到excel
- Android多媒体框架一
- Filtered off site request to
热门文章
- kotlin--综合运用Hilt、Paging3、Flow、Room、Retrofit、Coil等实现MVVM架构实战
- FAQ智能问答系统设计与实现
- 站在亚马逊的肩膀上:聊聊那些Purse为我们省下的钱
- DVWA靶场01-系统命令执行漏洞利用及防护(Low/Medium/Hight)
- 布尔函数——bool()
- 一种第N个红包最大实现的方式
- linux启动anaconda
- End-to-End Semi-Supervised Object Detection with Soft Teacher 解读
- 使用手机扫网页上的二维码便可快速在手机上访问网站
- 求解欧拉方程的c语言,用有限体积方法求解欧拉方程