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相关推荐

  1. 精尽 JDK 源码解析 —— 集合(五)哈希集合 HashSet

    1. 概述 HashSet ,基于 HashMap 的 Set 实现类.在业务中,如果我们有排重的需求,一般会考虑使用 HashSet . 在 Redis 提供的 Set 数据结构,不考虑编码的情况下 ...

  2. 精尽 JDK 源码解析 —— 集合(二)链表 LinkedList

    1. 概述 LinkedList ,基于节点实现的双向链表的 List ,每个节点都指向前一个和后一个节点从而形成链表. 相比 ArrayList 来说,我们日常开发使用 LinkedList 相对比 ...

  3. 精尽 JDK 源码解析 —— 集合(四)哈希表 LinkedHashMap

    1. 概述 众所周知,HashMap 提供的访问,是无序的.而在一些业务场景下,我们希望能够提供有序访问的 HashMap .那么此时,我们就有两种选择: TreeMap :按照 key 的顺序. L ...

  4. JDK源码解析 迭代器模式在JAVA的很多集合类中被广泛应用,接下来看看JAVA源码中是如何使用迭代器模式的。

    JDK源码解析 迭代器模式在JAVA的很多集合类中被广泛应用,接下来看看JAVA源码中是如何使用迭代器模式的. 看完这段代码是不是很熟悉,与我们上面代码基本类似.单列集合都使用到了迭代器,我们以Arr ...

  5. snabbdom源码解析(七) 事件处理

    事件处理 我们在使用 vue 的时候,相信你一定也会对事件的处理比较感兴趣. 我们通过 @click 的时候,到底是发生了什么呢! 虽然我们用 @click绑定在模板上,不过事件严格绑定在 vnode ...

  6. JDK源码解析 Comparator 中的策略模式

    JDK源码解析 Comparator 中的策略模式.在Arrays类中有一个 sort() 方法,如下: public class Arrays{public static <T> voi ...

  7. JDK源码解析 Runable是一个典型命令模式,Runnable担当命令的角色,Thread充当的是调用者,start方法就是其执行方法

    JDK源码解析 Runnable是一个典型命令模式, Runnable担当命令的角色,Thread充当的是调用者,start方法就是其执行方法 /命令接口(抽象命令角色) public interfa ...

  8. JDK源码解析 InputStream类就使用了模板方法模式

    JDK源码解析 InputStream类就使用了模板方法模式. 在InputStream类中定义了多个 read() 方法,如下: public abstract class InputStream ...

  9. JDK源码解析 Integer类使用了享元模式

    JDK源码解析 Integer类使用了享元模式. 我们先看下面的例子: public class Demo {public static void main(String[] args) {Integ ...

最新文章

  1. CentOS 6.4下PXE+Kickstart无人值守安装操作系统
  2. java安装好了打不开机_这都不犯规?王骁辉尺度把握得真好 难怪0+0+0能打20分钟...
  3. AndroidStudio设置背景颜色,字体大小,默认显示行号
  4. javaweb学习总结二十三(servlet开发之线程安全问题)
  5. 光流 | OpenCV实现简单的optical flow(代码类)
  6. linux安装磁盘分区设置,Linux安装与磁盘分区.doc
  7. 面经系列 | Python,数据结构,神经网络
  8. Matlab矩阵、元胞数组的合并拼接
  9. django无法生成自定义表(mysql)
  10. Flutter AnimatedSwitcher 实现优美的图片切换动画
  11. 弯道超车时机已来 百度:中国有机会定义AI时代的用户体验标准
  12. 【MYSQL快速入门】常用函数:日期函数
  13. 滞后问题_富锂正极材料的电压滞后问题
  14. bjui获取当前页签或者是dialog容器
  15. 内部推荐岗位信息201508
  16. 查看服务器sftp用户信息,linux查看sftp服务器配置
  17. Round14—最小生成树
  18. 如何使用Python提取pdf表格及文本,并保存到excel
  19. Android多媒体框架一
  20. Filtered off site request to

热门文章

  1. kotlin--综合运用Hilt、Paging3、Flow、Room、Retrofit、Coil等实现MVVM架构实战
  2. FAQ智能问答系统设计与实现
  3. 站在亚马逊的肩膀上:聊聊那些Purse为我们省下的钱
  4. DVWA靶场01-系统命令执行漏洞利用及防护(Low/Medium/Hight)
  5. 布尔函数——bool()
  6. 一种第N个红包最大实现的方式
  7. linux启动anaconda
  8. End-to-End Semi-Supervised Object Detection with Soft Teacher 解读
  9. 使用手机扫网页上的二维码便可快速在手机上访问网站
  10. 求解欧拉方程的c语言,用有限体积方法求解欧拉方程