调用初始化容量的构造函数,初始数组长度是多少
从其他地方读到HashMap是利用数组+链表的方式存储元素,默认数组长度为16,负载因子为0.75,一直也认为数组伴随着HashMap创建,一开始就初始化,并且长度也就是16,最近在被问到题目这个问题时,若是初始化容量为30,也就是调用new HashMap(30);,初始数组的长度是多少?突然懵了,不是很确定这个长度会是30,还是30*0.75呢?或者是其它值???
话不多说,源码撸起来
构造函数
//只传递初始化容量,负载因子还是默认的0.75
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
//如果初始化的容量大于最大容量,就将初始容量设置为最大允许容量 MAXIMUM_CAPACITY = 1 << 30
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();
}
从这个实际调用的构造函数来看,这里只是设置了属性 负载因子与阈值,并未真正的创建数组,那默认的数组长度是多少呢?
/**
* An empty table instance to share when the table is not inflated.
*/
static final Entry<?,?>[] EMPTY_TABLE = {};
/**
* The table, resized as necessary. Length MUST Always be a power of two.
*/
transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
可以看到,默认的table数组是一个空数组,也就是只调用了构造函数后,实际上并没有创建数组!!!
从源码来看,table数组赋值的地方有4处。
- 属性默认值,空数组
/**
* The table, resized as necessary. Length MUST Always be a power of two.
*/
transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
- 填充数组方法
/**
* Inflates the 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);
}
从这可以看到,新建数组的长度为2的次方。 inflateTable方法有以下几处调用



void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
Entry[] newTable = new Entry[newCapacity];
transfer(newTable, initHashSeedAsNeeded(newCapacity));
table = newTable;
threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
}
- 反序列化,设置为空数组
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException
{
...
// set other fields that need values
table = (Entry<K,V>[]) EMPTY_TABLE;
// Read in number of buckets
s.readInt(); // ignored.
...
}
从以上分析来看,当新建一个HashMap,若是并未使用,其实并没有初始化数组,若是调用put方法,懒初始化,其数组长度为32(2的5次方)。