HashMap作为java最常用的类之一,阅读其源码还是有助于理解内部原理,避免使用过程中不必要的错误;首先提出几个问题:
//TODO
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
从类的继承关系可以看出,继承AbstractMap,实现类Map<K,V>, Cloneable, Serializable,结构如下:
根据源码,进行逐步分析,先从类属性开始:
/**
* 初始容量为16,即默认如果创建map的时候不设置容量参数,
* 即系统默认为16,并且这里有个约定,容量大小必须为2的幂次方
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
/**
* 最大容量为2的30次方,即1073741824
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
/**
* 默认负载因子为0.75
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
- 问题: 为什么负载因子默认是0.75f?
- 问题:为什么容量必须为2的幂次方?
/**
* 节点由链表转换为树结构的节点数阀值
*/
static final int TREEIFY_THRESHOLD = 8;
/**
* 树结构转链表结构的节点数阀值
*/
static final int UNTREEIFY_THRESHOLD = 6;
/**
* 最小转换树结构的表容量,意思是如果容量小与该值,则直接进行扩容
*/
static final int MIN_TREEIFY_CAPACITY = 64;
HashMap内部类Node如下:
/**
* 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;
}
}
其主要实现来Map类的内部接口Entry;
可以发现在HashMap类里面,有很多内部类,
这里暂时不展开,等用到的时候根据需要进行适当的分析;下面按照初始化、查增改删的顺序进行分析;