HashMap 学习
部分源码解析
变量和常量
// 默认的初始化容量,十进制数为 16 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 // 极限容量,也就是说 table 数组再大也不能超过这个容量 static final int MAXIMUM_CAPACITY = 1 << 30; // 默认的负载因子:0.75(关系到 HashMap 本身的性能) static final float DEFAULT_LOAD_FACTOR = 0.75f; // 一个空的 Entry 数组,在 table 数组没有进行初始化扩容之前一直就是这个空数组 static final Entry<?,?>[] EMPTY_TABLE = {}; // HashMap 的存储结构就是这个 table 数组,长度为 2 的 n 次方数; // 数组中存储的元素是一个个 Entry 对象,而 Entry 对象又实现了链表结构; // 所以说 HashMap 的数据结构是 数组 + 链表,具体请看【存储结构】章节 transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE; // HashMap 存储的元素多少 transient int size; // 阀值,一般来说为 实际容量 * 负载因子 int threshold; // 实际的负载因子 final float loadFactor; // 修改次数,用于快速失败,具体请看【快速失败】章节 transient int modCount;
构造方法
public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); this.loadFactor = loadFactor; threshold = initialCapacity; init();// 此方法是空的 } public HashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR); } public HashMap() { this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); } public HashMap(Map<? extends K, ? extends V> m) { this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); inflateTable(threshold); putAllForCreate(m); }
(1). 前三个构造方法,无非就是设置一下初始化容量和负载因子,不多说。
(2). 而第四个构造方法:
- 设置初始化容量和负载因子;
- inflateTable(...) 初始化数组并扩充容量;
- 将 map 对象塞进空的 HashMap 中。
inflateTable(...)
// 对 table 数组进行扩容 private void inflateTable(int toSize) { // Find a power of 2 >= toSize int capacity = roundUpToPowerOf2(toSize); threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1); table = new Entry[capacity]; initHashSeedAsNeeded(capacity); } private static int roundUpToPowerOf2(int number) { // assert number >= 0 : "number must be non-negative"; return number >= MAXIMUM_CAPACITY ? MAXIMUM_CAPACITY : (number > 1) ? Integer.highestOneBit((number - 1) << 1) : 1; }
(1). 一直往前推,很容易得知传进来的 toSize 参数就是初始化容量;
(2). roundUpToPowerOf2(toSize) 方法得到返回值是一个比 toSize 大的最小的 2 的 n 次方数 capacity,capacity 就是实际容量;
- 若 toSize 为 15,则 capacity 为 16;若 toSize 为 17,则 capacity 为 32。因此可以看出: