java集合系列九:TreeMap源码解析

你应该先阅读java集合系列一:前传

java集合系列九:TreeMap源码解析_第1张图片

前提:阅读本文最好对红黑树有基本的了解

介绍

  • 扩展AbstractMap类并实现NavigatebleMap接口
  • 访问和检索时间相当短,这使得TreeMap成为存储需要快速找到的大量排序信息的绝佳选择
  • 树实现
  • 适用于按自然顺序或自定义顺序遍历键(key)
  • 不允许键为Null
  • 非线程安全
  • 具有fail-fast机制

继承关系 继承类介绍

AbstractMap:继承AbstractMap,它实现了Map接口,提供了Map接口的基本实现
NavigableMap:该接口继承自SortedMap接口,它的所有方法都是为定位设计的

变量解析(所有代码都不是完整的源码,而是精简过后的源码!结合源码食用更佳)

//比较器 用于维护映射的顺序 为null键使用自然排序
private final Comparator comparator;
//红黑树根节点
private transient Entry root;
//数据实际数量
private transient int size = 0;
//结构被修改次数
private transient int modCount = 0;

源码解析 常用方法解析

TreeMap.Entry

红黑树数据结构

static final class Entry implements Map.Entry {
    K key;
    V value;
    //左节点
    Entry left;
    //右节点
    Entry right;
    //父节点
    Entry parent;
    //节点颜色 root节点为黑色
    boolean color = BLACK;

put(K key, V value)

作用:将指定值与指定键关联

public V put(K key, V value) {
    Entry t = root;
    判断根节点是否为Null
    if (t == null) {
        compare(key, key); // type (and possibly null) check
        //构建一个节点指向根
        root = new Entry<>(key, value, null);
        size = 1;
        modCount++;
        return null;
    }
    int cmp;
    Entry parent;
    // split comparator and comparable paths
    Comparator cpr = comparator;
    //判断是否有比较器 默认为null 可在构造函数中设置
    if (cpr != null) {
    //使用比较器的compare方法比较key应该在left节点还是right节点
    //通过循环获取对应left或right节点的最后一个节点parent(当parent的下一个节点left/right为null时循环结束)
    //else中的判断也是一样的 区别在于if中使用的是自定义比较器 else中使用的是自然排序
        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)
            throw new NullPointerException();
        @SuppressWarnings("unchecked")
            Comparable k = (Comparable) key;
        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);
    }
    //构建节点 通过上面的循环已经拿到parent节点
    Entry e = new Entry<>(key, value, parent);
    //最后不管你的比较器(自然排序还是自定义的比较器)是什么 它只使用结果  将新节点链接到对应的left或right节点后
    if (cmp < 0)
        parent.left = e;
    else
        parent.right = e;
    //维护此树的特性(修改节点颜色或左旋右旋等操作)以保证其成为红黑树
    fixAfterInsertion(e);
    size++;
    modCount++;
    return null;
}

remove(Object key)

作用:从树的映射中删除键对应的映射

  //从根节点开始遍历 获取对应的节点
    Entry p = getEntry(key);
    if (p == null)
        return null;
    //获取value用于返回
    V oldValue = p.value;
    //删除此节点 重新维护此红黑树结构
    deleteEntry(p);
    return oldValue;

replace(K key, V value)

作用:替换指定键映射的值

	 //从根节点开始遍历 获取对应的节点
    Entry p = getEntry(key);
    if (p!=null) {
        V oldValue = p.value;
		//替换旧值
        p.value = value;
        return oldValue;
    }
    return null;
}

get(Object key)

作用:返回指定键映射到的值

	//从根节点开始遍历 获取对应的节点
    Entry p = getEntry(key);
    return (p==null ? null : p.value);	

你可能感兴趣的:(java,java集合深入浅出)