HashMap源码–(一)属性
HashMap是容器Map的实现类。
public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
HashMap继承了AbstractMap,AbstractMap是个抽象类,实现了Map,并实现了Map的主干方法,这样要实现Map只要继承AbstractMap并实现对应的entrySet()方法就可以。
这里HashMap继承了AbstractMap有实现了Map主要是让程序员明显的看到HashMap是Map的子类。
HashMap实现了Cloneable,表名调用Object.clone() 方法可以合法地对该类实例进行按字段复制,否则调用会报错。
HashMap实现Serializable,表名可以序列化。
HashMap的一些属性需要简述一下,以便理解其原理和方法:
/**
* 默认的初始容量,必须是2的幂.
*/
static final int DEFAULT_INITIAL_CAPACITY = 16;
/**
* 最大的容量值,用于通过构造器指定更大的值时所给定的值
* 也就是容量值必须小于等于1 << 30(2的30次幂)
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
/**
* 默认的加载因子.
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
* table是HashMap中存值的数组,它的长度是按需变化的,它的长度 *(length)通常是2的幂指数个.
*/
transient Entry<K,V>[] table;
/**
*Map中存放键值对的个数
*/
transient int size;
/**
* 加载阈值,下一次调整Map长度的临界值 (capacity * load factor).
* @serial
*/
int threshold;
/**
* HashMap的加载因子,在构造器中指定的.
* @serial
*/
final float loadFactor;
/**
* HashMap对象被结构性修改的次数, 譬如:put、remove,
* rehash操作 。这个属性主要用于多线程并发时发生的fail-fast。
*/
transient int modCount;
/**
* 应用在字符串键的备选哈希函数的容量阈值,这个备选哈希函数可
*以减少由于弱哈希值引起碰撞的概率。
*默认值是Integer.MAX_VALUE
*它可能被系统配置的属性值{@code jdk.map.althashing.threshold}
*覆盖。如果改属性值是1,备选哈希函数将被使用,如果是-1,备选
*哈希函数将永远不会被使用。
*/
static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;
HashMap实际也是用数组来存储元素,数组的大小可以在创建时指定大小,如果不指定则用默认的构造器容量为16,数组的大小是2的幂指数。HashMap中Entry<K,V>[] table
是用来接收元素,它的大小就是构造器指定的大小或默认的大小,即length。
size与length都是大小,但有不同的作用。length是HashMap的容量,即最多存储元素的数量。size是HashMap当前的存储的数量。
例:
Map map = new HashMap();
map.put(1, "one");
map.put(2, "two");
这里创建HashMap时用的是默认构造器,length为16,添加了两个元素,size是2。
HashMap在size/length达到一定比例时,需要扩大容量。加载因子loadFactor就是这个比例。加载因子可以在创造时指定,也可以用默认的值。对应的扩容的临界值size就是阈值threshold。当添加元素的数量达到阈值,容量会扩大2倍。
例如:容量length为16、加载因子loadFactor为0.75的HashMap,阈值threshold则为16*0.75=12,也就是在size达到阈值即12时,HashMap的容量变为16*2=32。