文章目录
前言
我们对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底层是基于红黑树实现了,所以他支持快速查询方法 并且它的构造器可传入了比较器可以自定义数据的排序方法