【JavaSE】TreeSet与TreeMap源码解读

简介: 文章目录1 TreeSet1.1 TreeSet快速入门1.2 TreeSet比较机制源码解读2 TreeMap2.1 TreeMap快速入门2.2 TreeMap比较机制源码解读写在最后

1 TreeSet

1.1 TreeSet快速入门

 相较于HashSet,TreeSet最大的特点是实现了排序,但是需要注意的是,当我们使用无参构造器创建TreeSet时,仍然是无序的。如果希望添加的元素按照字符串大小来排序则需要使用比较器Comparator,并指定排序规则。

来看下面的例子,可以看出,结果按照字符串大小进行了排序:

import java.util.Comparator;
import java.util.TreeSet;
/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 */
public class TreeSetTest {
    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("lucy");
        treeSet.add("drunk");
        treeSet.add("youth");
        treeSet.add("bob");
        treeSet.add("a");
        System.out.println("treeSet = " + treeSet);
    }
}


1.2 TreeSet比较机制源码解读

1️⃣ 构造器把传入的比较器对象,赋给了 TreeSet 底层的 TreeMap 属性。



2️⃣ 在调用 treeSet.add(“drunk”),底层会执行到下述代码,其中cpr 就是我们的匿名内部类(对象),会动态绑定到匿名内部类的compare方法。

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  // 如果相等,即返回0,这个key就没有加入
                    return t.setValue(value);
            } while (t != null);
        }

需要注意的是,当比较结果是相等时,不会将key添加进去!

我们来看下面的例子,尝试将比较规则更改为按照字符串长度排序:

import java.util.Comparator;
import java.util.TreeSet;
/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 */
public class TreeSetTest {
    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o2).length() -((String)o1).length();
            }
        });
        // 添加数据
        treeSet.add("Drunk");
        treeSet.add("Youth");
        System.out.println("treeSet = " + treeSet);
    }
}



由于 Drunk 与 Youth 长度相同,因此,在底层调用比较器的时候,不加入 Youth 这一 key 值。 这也是小白时期常常容易犯的错误,导致了数据的丢失!


2 TreeMap

2.1 TreeMap快速入门

当使用无参构造器的时候,TreeMap默认按照key值进行自然排序。

import java.util.TreeMap;
/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 */
public class TreeMapTest {
    public static void main(String[] args) {
        TreeMap treeMap = new TreeMap();
        // 添加数据
        treeMap.put("drunk", "路宝");
        treeMap.put("abc", "香克斯");
        treeMap.put("cat", "多弗朗明哥");
        System.out.println("treeMap = " + treeMap);
    }
}


也可以传入比较器,进行自定义排序。比如,尝试按照key的字符串长度的大小进行排序:

import java.util.Comparator;
import java.util.TreeMap;
/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 */
public class TreeMapTest {
    public static void main(String[] args) {
        TreeMap treeMap = new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o1).length() - ((String)o2).length();
            }
        });
        // 添加数据
        treeMap.put("drunk", "路宝");
        treeMap.put("abc", "香克斯");
        treeMap.put("cat", "多弗朗明哥");
        System.out.println("treeMap = " + treeMap);
    }
}

此时,由于 cat 和 abc 两个键的长度相同,因此,后面的 cat键没有成功加入,只是将 cat 对应的值 与 abc 对应的值进行了替换!





2.2 TreeMap比较机制源码解读

1️⃣ 调用构造器的时候,把传入的实现了 Comparator接口的匿名内部类(对象),赋给了 TreeMap 的属性 comparator;


2️⃣ 在执行第一个put时,加入了一个结点作为root根节点,把 k-v 封装到 Entry对象,放入root;



3️⃣ 之后调用 put 方法,会调用比较器。进行所有 key 的遍历,并动态绑定到匿名内部类的compare()方法。如果发现比当前结点小,则挂到左子树,大了就挂到右子树。如果相等,则只进行value的替换,key不会加入。 使用setValue方法进行。

    int cmp;
        Entry<K,V> parent;
        // split comparator and comparable paths
        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);
        }
相关文章
|
8天前
|
存储 Java uml
|
8天前
|
缓存 Java 程序员
Java Review - LinkedHashMap & LinkedHashSet 源码解读
Java Review - LinkedHashMap & LinkedHashSet 源码解读
35 0
Java Review - LinkedHashMap & LinkedHashSet 源码解读
|
8天前
HashSet 源码解读
HashSet 源码解读
9 1
|
8天前
ArrayList源码解读
ArrayList源码解读
6 1
|
11月前
|
存储 Java 容器
Java集合学习:ArrayList源码详解
Java集合学习:ArrayList源码详解
211 0
|
算法 Java
java TreeSet 和 TreeMap 源码解读
java 集合篇章——TreeSet 和 TreeMap 源码解读。
69 0
Java集合源码剖析——基于JDK1.8中HashSet、LinkedHashSet的实现原理
Java集合源码剖析——基于JDK1.8中HashSet、LinkedHashSet的实现原理
Java集合源码剖析——基于JDK1.8中HashSet、LinkedHashSet的实现原理
|
存储 安全 Java
Java集合简单了解——基于JDK1.8中LinkedHashMap、TreeMap、Hashtable、Properties的实现原理
Java集合简单了解——基于JDK1.8中LinkedHashMap、TreeMap、Hashtable、Properties的实现原理
Java集合简单了解——基于JDK1.8中LinkedHashMap、TreeMap、Hashtable、Properties的实现原理
|
存储 安全 Java
java集合系列(3)ArrayList(源码分析)
这篇文章开始介绍ArrayList。ArrayList基本上是我们在平时的开发当中,使用最多的一个集合类了,它是一个其容量能够动态增长的动态数组。所以这篇文章,旨在从源码的角度进行分析和理解。为了使得文章更加有条理,还是先给出这篇文章的大致脉络: 首先,ArrayList的基本介绍和源码API(只给出方法分析,重要的方法给出详细代码)。 然后,介绍遍历ArrayList的几种方式 接下来,叙述一下ArrayList与其他集合关键字的区别和优缺点 最后,进行一个总结
218 0
java集合系列(3)ArrayList(源码分析)
|
存储
【集合框架】JDK1.8源码分析HashSet && LinkedHashSet(八)
  分析完了List的两个主要类之后,我们来分析Set接口下的类,HashSet和LinkedHashSet,其实,在分析完HashMap与LinkedHashMap之后,再来分析HashSet与LinkedHashSet,就会变成异常简单,下面开始进行分析。
94 0

热门文章

最新文章