本博客将从源码的角度带领大家学习TreeSet相关的知识。

一TreeSet类的定义:

public class TreeSet<E> extends AbstractSet<E>implements NavigableSet<E>, Cloneable, java.io.Serializable

可以看到TreeSet是继承自AbstracSet同时实现了NavigableSet,Cloneable,Serializable三个接口,其中Cloneable,Serializable这两个接口基本上是java集合框架中所有的集合类都要实现的接口。

二TreeSet中的重要属性:

private transient NavigableMap<E,Object> m;private static final Object PRESENT = new Object();

可以看到第一个属性是NavigableMap接口,该接口是TreeMap的父接口,即TreeMap实现了该接口,据此我们可以推测TreeSet的底层是基于TreeMap的,这一点稍后我们将在TreeSet的构造器中更清楚的看到。第二个参数是以Object对象,与HashSet中的这个属性完全相同,即TreeSet虽然底层是基于TreeMap的,但是同样只是用来保存Key而Value值全部为默认值PRESENT。

三TreeSet内部实现原理:我们来看一下TreeSet的构造器:

TreeSet(NavigableMap<E,Object> m) {this.m = m;}public TreeSet() {this(new TreeMap<E,Object>());}public TreeSet(Collection<? extends E> c) {this();addAll(c);}public TreeSet(Collection<? extends E> c) {this();addAll(c);}public TreeSet(SortedSet<E> s) {this(s.comparator());addAll(s);}

可以看到共5个构造器,其中第一个构造器是私有的,即对外不公开的,而在第二个默认的无参数的构造器中调用了第一个构造器,且可以清楚的看到在这个构造器中创建了一个TreeMap对象作为参数传给第一个构造器,这说明我们上面的推测:TreeSet底层是基于TreeMap的是正确的。另外余下的几个构造器中可以看到当用一个集合作为参数去构造一个TreeSet的时候,都是调用addAll这个方法,我们来看一下其源码:

 public  boolean addAll(Collection<? extends E> c) {// Use linear-time version if applicableif (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;Comparator<?> cc = set.comparator();Comparator<? super E> mc = map.comparator();if (cc==mc || (cc != null && cc.equals(mc))) {map.addAllForTreeSet(set, PRESENT);return true;}}return super.addAll(c);}public boolean addAll(Collection<? extends E> c) {boolean modified = false;for (E e : c)if (add(e))modified = true;return modified;}public boolean add(E e) {return m.put(e, PRESENT)==null;}

可以看到在addAll方法中首先会判断是否传入的集合参数c是否为SortedSet或其子类且c不为空(c.size()>0),如果是则会调用addAllForTreeSet方法,否则会直接返回addAll方法的结果,关于addAll方法请参看我的博客 【java集合框架源码剖析系列】java源码剖析之HashSet相关内容,因为内容相同,在此不做赘述,重点来看一下addAllForTreeSet方法:

void addAllForTreeSet(SortedSet<? extends K> set, V defaultVal) {try {buildFromSorted(set.size(), set.iterator(), null, defaultVal);} catch (java.io.IOException cannotHappen) {} catch (ClassNotFoundException cannotHappen) {}}private void buildFromSorted(int size, Iterator<?> it,java.io.ObjectInputStream str,V defaultVal)throws  java.io.IOException, ClassNotFoundException {this.size = size;root = buildFromSorted(0, 0, size-1, computeRedLevel(size),it, str, defaultVal);}

可以看到在addAllForTreeSet方法中调用了buildFromSorted(int size, Iterator<?> it, java.io.ObjectInputStream str,V defaultVal),该方法的作用即是在线性时间内对数据进行排序(Linear time tree building algorithm from sorted data),看到这里我们就明白TreeSet排序的原理了,即当使用一个TreeMap集合作为参数构造一个TreeSet的时候,TreeSet会将Map中的元素先排序,然后将排序后的元素add到TreeSet中。也就是说TreeSet中的元素都是排过序的,另外正因为存在排序过程,所以TreeSet不允许插入null值,因为null值不能排序。

四TreeSet中的重要方法:

<strong> </strong>public boolean add(E e) {return m.put(e, PRESENT)==null;}public boolean remove(Object o) {return m.remove(o)==PRESENT;}public void clear() {m.clear();}public boolean contains(Object o) {return m.containsKey(o);}public E first() {return m.firstKey();}public E last() {return m.lastKey();}

可以看到TreeSet中与TreeMap中同名的方法全部都是调用的TreeMap中的方法来实现的,其中add方法在调用TreeMap的put方法时第二个参数传入的是固定值PRESENT,一个Object类型对象。

五总结:经过前面TreeMap的源码剖析可以看到TreeSet非常简单

1TreeSet底层是基于TreeMap的(而TreeMap是基于红黑树的),但是仅仅用来保存Key,而不保存Value,因为TreeSet的add()方法在调用TreeMap的put方法的时候第二个参数传入的都是PRESENT这个固定的Object对象。
2可以看到TreeSet中的add与remove等方法均无synchronized关键字修饰,即TreeSet不是线程安全的,如果要使用同步的TreeSet需要使用Collections集合类的静态方法,即Set s=Collections.synchronizedSet(new TreeSet());
3TreeSet中的元素是自动排好序的,插入的值不允许为null。

4TreeSet中元素的值必须是唯一的,因为TreeSet底层是基于TreeMap的,而TreeMap不允许元素key重复。

【java集合框架源码剖析系列】java源码剖析之TreeSet相关推荐

  1. java集合框架源代码_面试必备——Java集合框架

    Java集合框架面试题 常见集合 集合可以看作是一种容器,用来存储对象信息. 数组和集合的区别: (1)数组长度不可变化而且无法保存具有映射关系的数据:集合类用于保存数量不确定的数据,以及保存具有映射 ...

  2. Java集合框架——一个编程小白的Java SE学习日志11【极客BOY-米奇】

    文章目录 前言(转载请说明作者:极客BOY) 任务导引 List接口 特点 如何使用 ArrayList LinkedList List排序 前言(转载请说明作者:极客BOY) 2020.5.14 发 ...

  3. java集合框架支持三种类型,Java集合框架(一)

    集合类存放于java.util包中,集合类存放的都是对象的引用,而非对象本身,出于表达上的便利,我们称集合中的对象就是指集合中对象的引用(reference) 集合类型主要有3种:set(集).lis ...

  4. java集合框架总结(一)

    为什么80%的码农都做不了架构师?>>>    本系列博客详细介绍了JAVA集合框架,你将知道: 一.学习目标 1)java集合框架的层次结构 2)使用Collection接口定义的 ...

  5. Java集合框架底层原理

    Java集合框架 Java集合框架 List集合 ArrayList底层实现原理 ArrayList数组扩容技术(数组拷贝) 扩容大小 查询和删除 集合中的泛型 LinkedList Vector 线 ...

  6. Java集合框架:总结

    欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...

  7. Java集合框架使用总结

    Java集合框架使用总结 前言: 本文是对Java集合框架做了一个概括性的解说,目的是对Java集合框架体系有个总体认识,如果你想学习具体的接口和类的使用方法,请参看JavaAPI文档. 一.概述 数 ...

  8. Java 集合框架 详解

    一.Java 集合框架概述 集合框架是一个用来代表和操纵集合的统一架构(java集合框架位于java.util包中).所有的集合框架都包含如下内容: 接口:是代表集合的抽象数据类型.例如 Collec ...

  9. 【java集合框架源码剖析系列】java源码剖析之ArrayList

    注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本. 本博客将从源码角度带领大家学习关于ArrayList的知识. 一ArrayList类的定义: public class Arr ...

  10. 【java集合框架源码剖析系列】java源码剖析之java集合中的折半插入排序算法

    注:关于排序算法,博主写过[数据结构排序算法系列]数据结构八大排序算法,基本上把所有的排序算法都详细的讲解过,而之所以单独将java集合中的排序算法拿出来讲解,是因为在阿里巴巴内推面试的时候面试官问过 ...

最新文章

  1. 全球第一所人工智能大学成立:培养硕博研究生,全员全额奖学金
  2. mxnet基础到提高(11)--循环
  3. 质因数的个数 (分解质因数)
  4. 线段树 + 矩阵 --- ZOJ 3772 Calculate the Function
  5. 在导出php,PHP导出通用方法
  6. js打开新窗口的两种方式
  7. oracle窗口累计函数,oracle 窗口函数 (keep)
  8. python3常用内置函数总结
  9. 64位电脑 装32位oracle,64位Windows可以安装32位的Oracle吗
  10. iphone 利用UIImageView来制作幻灯片
  11. C++字符串输入输出操作
  12. 搭搭云配置系统概述-表单
  13. ueditor html模板,UEditor 编辑模板
  14. php根据身份证号码确定地区(省份)地址
  15. 基于RetinaFace+ArcFace的人脸识别测试和验证代码
  16. 高斯过程回归matlab,高斯过程回归及其应用.PDF
  17. 数字转换大写英文字母
  18. 第六章 字典(访问、修改、遍历)
  19. 记一次 JVM CPU 使用率飙高问题的排查过程
  20. 一起学爬虫(Python) — 09

热门文章

  1. eplan2.7在win10安装教程
  2. CorelDRAWX4的VBA插件开发(三十六)调用C++实现一键智能群组(第5节)导出动态链接库并在VBA中静态调用
  3. html 做成ppt样式,HTML开发网页样式.ppt
  4. Win 10间歇性卡顿问题
  5. ArcGIS API For JavaScript - 地图常用函数方法
  6. js字体溢出字体变小_可变字体:它们是什么,以及如何使用它们
  7. 基于麻雀搜索算法优化的Elman神经网络数据预测 - 附代码
  8. ADC的DMA多通道数据采集(雨滴传感器+光敏传感器)
  9. TP LINK交换机 console 超级终端链接设置
  10. 无法定位链接器!请检查 tools\link.ini 中的配置是否正确。 易语言5.9版本 静态编译