LinKedHashMap和TreeMap介绍


前言

我们对LinKedHashMap和TreeMap研究都是基于HashMap为参考来研究一下他们独有的特点,和维护这些特点的方法。


提示:以下是本篇文章正文内容,下面案例可供参考

一、LinKedHashMap源码分析:

LinKedHashMap继承自HashMap<K,V> 具有HashMap的所有特性:Key不能重复、Key value都可以为null 线程不安全
相比HashMap来说LinkedHashMap具有有序性(插入有序)

继承关系:

public class LinkedHashMap<K,V>
 		extends HashMap<K,V>
    		implements Map<K,V>

可以看出LinkedHashMap是基于HashMap实现的

属性:

默认值、扩容机制都和HashMap的特征一样
特有的属性:

transient LinkedHashMap.Entry<K,V> head;//头结点
transient LinkedHashMap.Entry<K,V> tail;//尾结点

构造器:

构造器调用HashMap的构造器
新增一个构造器:
boolean型的accessOrder 用来判断顺序性
true 访问有序 false 插入有序 默认值:false

public LinkedHashMap(int initialCapacity,
                         float loadFactor,
                         boolean accessOrder) {
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
    }

私有内部类

Entry<K,V>内部类继承与HashMap的内部类Node 增加了 head tail 用来保证有序性。
注释:插入有序即 按照插入时的顺序保持有序 访问有序即访问后将此数据移动到末尾。

static class Entry<K,V> extends HashMap.Node<K,V> {
        Entry<K,V> before, after; //前缀和后缀
        Entry(int hash, K key, V value, Node<K,V> next) {
            super(hash, key, value, next);
        }
    }

put 方法:

直接使用put方法调用的是父类的put方法但在put方法里面调用的newNode方法是子类重写的


public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }
inal V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
	//判断数组是否为空,为空则对tab进行扩容扩容后将新数组的长度赋值给n。
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
	//判断此hash对应的数组位置是否为Null 如果为null 用子类newNode方法赋值
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
	//先判断链表首位的hash和此新传入的hash是否相等在判断k值是否相等,相等的话将首尾p赋值给e
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
	//判断p是否在红黑树上
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
	//不在红黑树也不在首位的话遍历链表
                for (int binCount = 0; ; ++binCount) {
		//如果遍历到末尾给末尾赋值新创建的newNide;
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
		//如果遍历到链表长度之外的话
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
	//如果hash值与链表中以为hash值相等或者K值相等的话退出循环
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
	//更新p
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

//子类:
 Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
	新建一个Entry 赋值给 P      
  LinkedHashMap.Entry<K,V> p =
            new LinkedHashMap.Entry<>(hash, key, value, e);
	使用linkNodeLast方法对p进行重新操作(更新头结点,尾结点和前缀后缀等属性)
        linkNodeLast(p);
        return p;
    }
private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
        LinkedHashMap.Entry<K,V> last = tail;
        tail = p;
	//如果尾结点为null说明此链表之前没有Entry<K,V>将p赋值给头结点head
	// 否则更新p的前缀为之前的尾结点原来尾结点的后缀更新为P
        if (last == null)
            head = p;
        else {
            p.before = last;
            last.after = p;
        }
    }

LinKedHashMap总结

从上面我们可以看出LinKedHashMap相比于HashMap保证的数据的有序性,他的有序性保证是在HashMap原有的基础上给每个数据添加了双向链表来达到数据的有序性

二、TreeMap源码分析:

TreeMap保证map的key可以大小排序,key不能为null (NullPointerException)value可以为null,key不能重复

继承关系:

继承AbstractMap所有方法
实现了 NavigableMap和Serializable(可序列化)接口

public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable

我们来介绍一下 NavigableMap主要作用就不分析源码了

1. NavigableMap 继承自 SortedMap,所以它的元素是有序的。
2. 在 SortedMap 基础上,支持快速搜索符合条件的最近的元素。这里条件主要是指 	lower(>), floor(>=), ceiling(<),higher(>)。
3. 支持逆序访问。 descendingKeySet / descendingMap。
4. 支持获取子集合,集合边界元素是否包含是可配的 subMap headMap  tailMap 。

通过上述我们就可以知道TreeMap同样也具备如上的功能

属性:

public Comparator<? super K> comparator() { //比较器
        return comparator;
    }
 private transient Entry<K,V> root = null; //root属性,红黑树的根节点,是entry类型entry节点根据key进行排序

构造器:

相比于HashMap来说提供了比较器用来对数据进行排序

//空参构造器使用默认比较器
public TreeMap() {
        comparator = null;
    }
//实现comparator的构造器
    public TreeMap(Comparator<? super K> comparator) {
        this.comparator = comparator;
    }

//传入数据的构造器   
    public TreeMap(Map<? extends K, ? extends V> m) {
        comparator = null;
        putAll(m);
    }

//带有comparator方法的类 
    public TreeMap(SortedMap<K, ? extends V> m) {
        comparator = m.comparator();
        try {
            buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
        } catch (java.io.IOException | ClassNotFoundException cannotHappen) {
        }
    }

私有内部类

相比较HashMap来说内部类Entry增加了左右孩子父节点还有颜色的属性来实现红黑树储存数据

static final class Entry<K,V> implements Map.Entry<K,V> {
        K key;	//键
        V value;	//值
        Entry<K,V> left;	//左孩子
        Entry<K,V> right;	//右孩子
        Entry<K,V> parent;	//父节点
        boolean color = BLACK;	//颜色 默认黑色

        Entry(K key, V value, Entry<K,V> parent) {
            this.key = key;
            this.value = value;
            this.parent = parent;
        }

方法:

因为TreeMap继承自NavigableMap的所以也具有他的一些方法:
lower(>), floor(>=), ceiling(<),higher(>) //快速查找
descendingKeySet / descendingMap //逆序访问
subMap headMap tailMap //获取子集合

TreeMap总结:

TreeMap底层是基于红黑树实现了,所以他支持快速查询方法 并且它的构造器可传入了比较器可以自定义数据的排序方法

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值