ArrayList、HashMap等集合初始容量的大小以及扩容的倍数

比较

集合 默认初始化大小 扩容大小
ArrayList 10 1.5
Vector 10 2(默认)
HashMap 16 2(阈值0.75)
HashTable 11 2倍+1(阈值0.75)

ArrayList

无参构造器

由无参方法我们可以得到ArrayList如果不指定数组大小则它开始的大小为0,如果我们指定了初始大小,则elementData 的初始大小就变成了我们所指定的初始大小了

#无参构造方法
public ArrayList() {
 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

//默认的空数组常量
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMEN TDATA = {};

首次使用

默认容量大小为10

在插入元素之前,它会先检查是否需要扩容,然后再把元素添加到数组中最后一个元素的后面。在 ensureCapacityInternal 方法中,

我们可以看见,如果当 elementData 为空数组时,它会使用默认的大小去扩容。所以说,通过无参构造方法来创建 ArrayList 时,它的大小其实是为 0 的,只有在使用到的时候,才会通过 grow 方法去创建一个大小为 10 的数组。

private static final int DEFAULT_CAPACITY = 10;

扩容

grow 方法是在数组进行扩容的时候用到的,从中我们可以看见,ArrayList 每次扩容都是扩 1.5 倍,然后调用 Arrays 类的 copyOf 方法,把元素重新拷贝到一个新的数组中去。

private void grow(int minCapacity) {
 // overflow-conscious code
 int oldCapacity = elementData.length;
 //右移相当于除2在加上原来的部分就成为了1.5倍
 int newCapacity = oldCapacity + (oldCapacity >> 1);
    
 if (newCapacity - minCapacity < 0)
 newCapacity = minCapacity;
 if (newCapacity - MAX_ARRAY_SIZE > 0)
 newCapacity = hugeCapacity(minCapacity);
 // minCapacity is usually close to size, so this is a wi
n:
 elementData = Arrays.copyOf(elementData, newCapacity);
}

Vector

Vector 比 ArrayList 多了一个属性:

这个属性是在扩容的时候用到的,它表示每次扩容只扩 capacityIncrement 个空间就足够了。该属性可以通过构造方法给它赋值。先来看一下构造方法:

protected int capacityIncrement;

构造方法

// 初始化容器大小,和每次扩容大小
public Vector(int initialCapacity, int capacityIncrement) 
{
 super();
 if (initialCapacity < 0)
 throw new IllegalArgumentException("Illegal Capacit
y: "+initialCapacity);
 this.elementData = new Object[initialCapacity];
 this.capacityIncrement = capacityIncrement;
}
//初始化容器大小
public Vector(int initialCapacity) {
 this(initialCapacity, 0);
尚硅谷 Java 高级编程 宋红康
}
//无参构造初始化容量为10
public Vector() {
 this(10);
}

简单总结一下:这三种构造方法

  • 无参构造
  • 可以设置初始化容量
  • 也可初始化容量和每次扩充的大小

从构造方法中,我们可以看出 Vector 的默认大小也是 10,而且它在初始化的时候就

已经创建了数组了。

扩容

private void grow(int minCapacity) {
 // overflow-conscious code
 int oldCapacity = elementData.length;
 int newCapacity = oldCapacity + ((capacityIncrement > 
0) ? capacityIncrement : oldCapacity);
 if (newCapacity - minCapacity < 0)
 newCapacity = minCapacity;
 if (newCapacity - MAX_ARRAY_SIZE > 0)
 newCapacity = hugeCapacity(minCapacity);
 elementData = Arrays.copyOf(elementData, newCapacity);
}

如果指定了扩容的大小( capacityIncrement),则按照指定的大小进行扩容。

如果没有指定扩容的大小,则每次扩容为之前的两倍。

HashMap

//默认的初始容量为 16
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
//最大的容量上限为 2^30
static final int MAXIMUM_CAPACITY = 1 << 30;
//默认的负载因子为 0.75
static final float DEFAULT_LOAD_FACTOR = 0.75f;
尚硅谷 Java 高级编程 宋红康
//变成树型结构的临界值为 8
static final int TREEIFY_THRESHOLD = 8;
//恢复链式结构的临界值为 6
static final int UNTREEIFY_THRESHOLD = 6;
//当哈希表的大小超过这个阈值,才会把链式结构转化成树型结构,否则仅采取扩容来尝试减少冲突
static final int MIN_TREEIFY_CAPACITY = 64;

长活短说:

  • 初始化默认容量为16
  • 扩容阈值为0.75,意思就是每次达到现在容量的0.75倍是就进行扩容(此处不是占用桶的个数,而是键值对的数量)
  • 如果需要扩容,变为原来容量的两倍
  • 如果一个桶中的链表长度超过8,并且哈希表的容量大于64时,则转换为树结构
  • 如果树的深度地于6则又转换为链式结构

HashTable

构造器

public Hashtable(int initialCapacity) {
 this(initialCapacity, 0.75f);
}
public Hashtable() {
 this(11, 0.75f);
}

默认容量为11,扩容的阈值为0.75

//扩容扩为原来的两倍+1
 int newCapacity = (oldCapacity << 1) + 1;

扩容时,容量为原来的两倍+1

你可能感兴趣的:(JAVA,java,Java集合)