* @see HashMap
* @see TreeMap
* @see Hashtable
* @see SortedMap
* @see Collection
* @see Set
HashMap继承自AbstractMap类,AbstractMap类实现Map接口。
一、HashMap中的常量(此处我的JDK是1.8):
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
默认初始化的HashMap容量大小,即2^4 = 16,初始化一个容量大小为16的HashMap。
static final int MAXIMUM_CAPACITY = 1 << 30;
HashMap最大的容量,即2^30 = 1073741824,HashMap最大容量为这个,如果超过该大小,则以该大小为当前HashMap容量。
static final float DEFAULT_LOAD_FACTOR = 0.75f;
HashMap的默认负载因子,即实际最大容量 / 初始最大容量 的比值,当实际最大容量超过 初始最大容量*负载因子 时,HashMap则进行扩容。
static final int TREEIFY_THRESHOLD = 8;
HashMap中解决hash冲突的链表长度超过8时,发生hash冲突的数据数据结构会由链表变成树
static final int UNTREEIFY_THRESHOLD = 6;
HashMap在扩容时,如果发现树节点少于6个时,HashMap中的树结构会退回链表结构
static final int MIN_TREEIFY_CAPACITY = 64;
HashMap中链表转树结构前的HashMap中键值对的最小数量,键值对数量不超过 64个,则不进行链表转树操作,MIN_TREEIFY_CAPACITY的值至少是TREEIFY_THRESHOLD的值的4倍。
二、HashMap中的几个全局变量介绍:
/**
* The table, initialized on first use, and resized as
* necessary. When allocated, length is always a power of two.
* (We also tolerate length zero in some operations to allow
* bootstrapping mechanics that are currently not needed.)
*/
transient Node<K,V>[] table;
节点数组,因为HashMap的结构是有数组和链表(红黑树),所以table是用来存放key-value键值对的数组。
/**
* Holds cached entrySet(). Note that AbstractMap fields are used
* for keySet() and values().
*/
transient Set<Map.Entry<K,V>> entrySet;
键值对的Set集合,HashMap的另一种数据存储方式,该变量存放的是EntrySet的实例。EntrySet是HashMap的一个内部类(后面会讲到),主要的用处是对HashMap进行迭代操作。该变量通过HashMap的entrySet()方法进行初始化。
/**
* The number of key-value mappings contained in this map.
*/
transient int size;
HashMap中key-value键值对的实际数量,这个变量的值 和 HashMap中key-value键值对的数组table长度不一定相同。因为HashMap中可能包含链表或红黑树,所以,这个变量的值可能会大于table数组的长度。
/**
* The number of times this HashMap has been structurally modified
* Structural modifications are those that change the number of mappings in
* the HashMap or otherwise modify its internal structure (e.g.,
* rehash). This field is used to make iterators on Collection-views of
* the HashMap fail-fast. (See ConcurrentModificationException).
*/
transient int modCount;
该变量代表HashMap被修改的次数,这个变量用于迭代过程中的Fail-Fast机制,如果在某个线程操作HashMap时发现此线程备份的modCount和当前的modCount大小不相同时,可以快速抛出异常(ConcurrentModificationException)并终止操作,但是快速失败策略不能保证线程安全。
/**
* The next size value at which to resize (capacity * load factor).
*
* @serial
*/
// (The javadoc description is true upon serialization.
// Additionally, if the table array has not been allocated, this
// field holds the initial array capacity, or zero signifying
// DEFAULT_INITIAL_CAPACITY.)
int threshold;
HashMap进行扩容的阈值大小,该变量的大小等于HashMap容量*负载因子,即:threshold = capacity * load factor。
/**
* The load factor for the hash table.
*
* @serial
*/
final float loadFactor;
负载因子,即HashMap进行扩容时的阈值和容量的比值。
三、HashMap中的内部类介绍:
1、Node<K,V> 类:
/**
* Basic hash bin node, used for most entries. (See below for
* TreeNode subclass, and in LinkedHashMap for its Entry subclass.)
*/
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
Node<K,V> 类实现 Map.Entry<K,V>接口,参数有四个:
final int hash; //hash值
final K key; //键值对的key值
V value; //键值对的value值
Node<K,V> next; //下一个Node节点的值
提供的方法:一个有参的构造方法、key和value的get方法、value的set方法、toString方法、以及重写的equals和hashCode方法。其中setValue方法在set成功后会把value的老值当做结果返回。
2、KeySet 类:
final class KeySet extends AbstractSet<K> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
public final Iterator<K> iterator() { return new KeyIterator(); }
public final boolean contains(Object o) { return containsKey(o); }
public final boolean remove(Object key) {
return removeNode(hash(key), key, null, false, true) != null;
}
public final Spliterator<K> spliterator() {
return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
}
public final void forEach(Consumer<? super K> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e.key);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}
该内部类继承自AbstractSet,AbstractSet是Set的实现类。所以KeySet具有Set的所有特性。顾名思义,该Set集合是存放着HashMap键值对中key值的集合。
该内部类提供的方法有:
①、size()方法
public final int size() { return size; }
返回 HashMap中key-value键值对的实际数量,即HashMap的大小,也是KeySet的大小。
②、clear()方法
public final void clear() { HashMap.this.clear(); }
调用HashMap的clear方法,清空HashMap,以达到清空KeySet的目的。我们看下HashMap中的clear方法源码:
/**
* Removes all of the mappings from this map.
* The map will be empty after this call returns.
*/
public void clear() {
Node<K,V>[] tab; //定义一个Node数组tab
modCount++; //让HashMap的修改次数做一次自增
if ((tab = table) != null && size > 0) { //将HashMap的Node数组table的引用赋给tab,
//判断tab是否为空,并且
//HashMap中键值对数量是否大于0
//如果条件满足
size = 0; //让HashMap中的size等于0
for (int i = 0; i < tab.length; ++i) //遍历HashMap的Node数组,
tab[i] = null; //让HashMap中每一个Node元素的值都为null,
}
}
③、iterator()方法
public final Iterator<K> iterator() { return new KeyIterator(); }
该方法返回KeyIterator类的实例,KeyIterator继承HashIterator类,实现Iterator接口,我们看一下内部类KeyIterator及与其相似的ValueIterator类和EntryIteraror类的源码:
final class KeyIterator extends HashIterator
implements Iterator<K> { //对HashMap中的Key值进行循环操作的Iterator
public final K next() { return nextNode().key; }
}
final class ValueIterator extends HashIterator
implements Iterator<V> { //对HashMap中的value值进行循环操作的Iterator
public final V next() { return nextNode().value; }
}
final class EntryIterator extends HashIterator
implements Iterator<Map.Entry<K,V>> { //对Map中的Entry键值对进行循环操作的Iterator
public final Map.Entry<K,V> next() { return nextNode(); }
}
我们发现这三个类都只有一个final修饰的next()方法,而方法体内都调用了nextNode()方法,这里的nextNode()方法是它们父类HashIterator类的方法,我们看下它们父类HashIterator的源码,以及nextNode()方法的实现。
// iterators
//HashMap中的Node是继承自Map的Entry类的,所以我们这里就把Node和Entry归为一类了。
abstract class HashIterator {
Node<K,V> next; // next entry to return 下一个Node键值对
Node<K,V> current; // current entry 当前的Node键值对
int expectedModCount; // for fast-fail 期望的HashMap被修改次数,
//在快速-失败策略上使用的
int index; // current slot //当前的位置索引
HashIterator() { //无参构造器
expectedModCount = modCount; //将当前HashMap的修改次数赋给expectedModCount
Node<K,V>[] t = table; //将HashMap的当前Node数组赋值t
current = next = null; //初始化current和next都为null
index = 0; //初始化当前索引为0
if (t != null && size > 0) { // advance to first entry
do {} while (index < t.length && (next = t[index++]) == null);
}
}
public final boolean hasNext() {
return next != null;
}
final Node<K,V> nextNode() {
Node<K,V>[] t;
Node<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
if ((next = (current = e).next) == null && (t = table) != null) {
do {} while (index < t.length && (next = t[index++]) == null);
}
return e;
}
public final void remove() {
Node<K,V> p = current;
if (p == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
current = null;
K key = p.key;
removeNode(hash(key), key, null, false, false);
expectedModCount = modCount;
}
}
未完待续~~~2018-12-15