If you look at the implementation of HashMap, the constructor looks like:
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();
}
And init() looks like:
/**
* Initialization hook for subclasses. This method is called
* in all constructors and pseudo-constructors (clone, readObject)
* after HashMap has been initialized but before any entries have
* been inserted. (In the absence of this method, readObject would
* require explicit knowledge of subclasses.)
*/
void init() {
}
So initialCapacity doesn’t actually get used to create an array. Where does it get used? Look at the put() method.
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
// hidden
}
When doing a put, the array is actually created. I didn’t show inflateTable() but it does some math and initializes the array.