HashMap我们了解过了,LinkedHasHMap来实现LRU也介绍过了,有兴趣的可以参阅 Lru实现原理——LinkedHashMap源码解析
现在我们来了解一下TreeMap.
public class TreeMap
extends AbstractMap
implements NavigableMap, Cloneable, java.io.Serializable
{
/**
* The comparator used to maintain order in this tree map, or
* null if it uses the natural ordering of its keys.
*
* @serial
*/
private final Comparator super K> comparator;
private transient Entry root;
/**
* The number of entries in the tree
*/
private transient int size = 0;
/**
* The number of structural modifications to the tree.
*/
private transient int modCount = 0;
public TreeMap() {
comparator = null;
}
public TreeMap(Comparator super K> comparator) {
this.comparator = comparator;
}
public TreeMap(Map extends K, ? extends V> m) {
comparator = null;
putAll(m);
}
public TreeMap(SortedMap m) {
comparator = m.comparator();
try {
buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
} catch (java.io.IOException cannotHappen) {
} catch (ClassNotFoundException cannotHappen) {
}
}
下边我们来查看一下TreeMap的Entry.
static final class Entry implements Map.Entry {
K key;
V value;
Entry left;
Entry right;
Entry parent;
boolean color = BLACK;
/**
* Make a new cell with given key, value, and parent, and with
* {@code null} child links, and BLACK color.
*/
Entry(K key, V value, Entry parent) {
this.key = key;
this.value = value;
this.parent = parent;
}
/**
* Returns the key.
*
* @return the key
*/
public K getKey() {
return key;
}
/**
* Returns the value associated with the key.
*
* @return the value associated with the key
*/
public V getValue() {
return value;
}
/**
* Replaces the value currently associated with the key with the given
* value.
*
* @return the value associated with the key before this method was
* called
*/
public V setValue(V value) {
V oldValue = this.value;
this.value = value;
return oldValue;
}
public boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry,?> e = (Map.Entry,?>)o;
return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
}
public int hashCode() {
int keyHash = (key==null ? 0 : key.hashCode());
int valueHash = (value==null ? 0 : value.hashCode());
return keyHash ^ valueHash;
}
public String toString() {
return key + "=" + value;
}
}
非常明显,Entry是一个二叉树结构。
最重要的是来关注一下TreeMap的put方法,是如何实现有序的。
public V put(K key, V value) {
Entry t = root;
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 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);
}
else {
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable super K> k = (Comparable super K>) 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);
}
Entry e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
现在就来看它是如何实现有序的,我们来查看它的遍历方法。
public Set keySet() {
return navigableKeySet();
}
public NavigableSet navigableKeySet() {
KeySet nks = navigableKeySet;
return (nks != null) ? nks : (navigableKeySet = new KeySet<>(this));
}
KeySet内部全部还是调用TreeMap的方法。
static final class KeySet extends AbstractSet implements NavigableSet {
private final NavigableMap m;
KeySet(NavigableMap map) { m = map; }
public Iterator iterator() {
if (m instanceof TreeMap)
return ((TreeMap)m).keyIterator();
else
return ((TreeMap.NavigableSubMap)m).keyIterator();
}
public Iterator descendingIterator() {
if (m instanceof TreeMap)
return ((TreeMap)m).descendingKeyIterator();
else
return ((TreeMap.NavigableSubMap)m).descendingKeyIterator();
}
public int size() { return m.size(); }
public boolean isEmpty() { return m.isEmpty(); }
public boolean contains(Object o) { return m.containsKey(o); }
public void clear() { m.clear(); }
public E lower(E e) { return m.lowerKey(e); }
public E floor(E e) { return m.floorKey(e); }
public E ceiling(E e) { return m.ceilingKey(e); }
public E higher(E e) { return m.higherKey(e); }
public E first() { return m.firstKey(); }
public E last() { return m.lastKey(); }
public Comparator super E> comparator() { return m.comparator(); }
public E pollFirst() {
Map.Entry e = m.pollFirstEntry();
return (e == null) ? null : e.getKey();
}
public E pollLast() {
Map.Entry e = m.pollLastEntry();
return (e == null) ? null : e.getKey();
}
public boolean remove(Object o) {
int oldSize = size();
m.remove(o);
return size() != oldSize;
}
public NavigableSet subSet(E fromElement, boolean fromInclusive,
E toElement, boolean toInclusive) {
return new KeySet<>(m.subMap(fromElement, fromInclusive,
toElement, toInclusive));
}
public NavigableSet headSet(E toElement, boolean inclusive) {
return new KeySet<>(m.headMap(toElement, inclusive));
}
public NavigableSet tailSet(E fromElement, boolean inclusive) {
return new KeySet<>(m.tailMap(fromElement, inclusive));
}
public SortedSet subSet(E fromElement, E toElement) {
return subSet(fromElement, true, toElement, false);
}
public SortedSet headSet(E toElement) {
return headSet(toElement, false);
}
public SortedSet tailSet(E fromElement) {
return tailSet(fromElement, true);
}
public NavigableSet descendingSet() {
return new KeySet<>(m.descendingMap());
}
public Spliterator spliterator() {
return keySpliteratorFor(m);
}
}
Iterator keyIterator() {
return new KeyIterator(getFirstEntry());
}
final class KeyIterator extends PrivateEntryIterator {
KeyIterator(Entry first) {
super(first);
}
public K next() {
return nextEntry().key;
}
}
abstract class PrivateEntryIterator implements Iterator {
Entry next;
Entry lastReturned;
int expectedModCount;
PrivateEntryIterator(Entry first) {
expectedModCount = modCount;
lastReturned = null;
next = first;
}
public final boolean hasNext() {
return next != null;
}
final Entry nextEntry() {
Entry e = next;
if (e == null)
throw new NoSuchElementException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
next = successor(e);
lastReturned = e;
return e;
}
final Entry prevEntry() {
Entry e = next;
if (e == null)
throw new NoSuchElementException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
next = predecessor(e);
lastReturned = e;
return e;
}
public void remove() {
if (lastReturned == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
// deleted entries are replaced by their successors
if (lastReturned.left != null && lastReturned.right != null)
next = lastReturned;
deleteEntry(lastReturned);
expectedModCount = modCount;
lastReturned = null;
}
}
//找到当前节点的下一个节点
static TreeMap.Entry successor(Entry t) {
if (t == null)
return null;
else if (t.right != null) {
Entry p = t.right;
while (p.left != null)
p = p.left;
return p;
} else {
Entry p = t.parent;
Entry ch = t;
while (p != null && ch == p.right) {
ch = p;
p = p.parent;
}
return p;
}
}
predecessor也是类似的,大家可以自行研究,另外entrySet最后也是调用PrivateEntryIterator的nextEntry方法,在这里就不重复分析了。
到此为止,我们明白了,TreeMap顾名思义就是使用Tree来存储数据的,遍历的时候也是通过二叉树的特点来查找下一个节点的,然后保证有序。