ArrayList
ArrayList是list接口的重要实现类。其作为动态数组存在,可以不断扩充数组大小。注意ArrayList是线程不安全的。反之,vector是线程安全的,两者的主要用途是一致的。
扩容机制
- ArrayList支持初始化时提供一个list大小initialCapacity,如果不提供,则默认值为0。
- 加入元素的时候扩容elementData为10,在这之后,每当我们往其中加入数据超出限制,都会让list扩容当前容量的1.5倍。
- 如果提供初始initialCapacity,则只有加入元素超限时才会扩容当前容量的1.5倍。
源码
动态数组本质
ArrayList使用的一个数组Object[] elementData来实现数据的存储。对于不同的ArrayList初始化方法,elementData会被初始化为不同的数组。
//transient关键字表示该属性不会被序列化
transient Object[] elementData;
//无参构造器中使用的数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//空数组,有参构造器中使用
private static final Object[] EMPTY_ELEMENTDATA = {};
构造器
首先,无参构造器允许我们创建一个空数组
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
指定构造器
public ArrayList(int initialCapacity) {
//直接为指定的大小分配一个初始容量
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
//如果给出的大小为0,认定这是一个空数组EMPTY_ELEMENTDATA
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
add方法
对于add方法,源码如下
//对外的接口
public boolean add(E e) {
//modCount负责记录集合被修改的次数
modCount++;
//调用重载的add方法
add(e, elementData, size);
return true;
}
//实际执行的add重载方法
private void add(E e, Object[] elementData, int s) {
//首先查看size是否已经超出了限制
if (s == elementData.length)
//如果超出,执行grow使数组扩容
elementData = grow();
//空间充足时,数组[s] = e;
elementData[s] = e;
size = s + 1;
}
扩容
主要的扩容机制通过grow函数实现。
private Object[] grow(int minCapacity) {
int oldCapacity = elementData.length;
//如果elementData不为空
//或者elementData不是DEFAULTCAPACITY_EMPTY_ELEMENTDATA
//即使用了有参构造器构造的Arraylist
if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
int newCapacity = ArraysSupport.newLength(oldCapacity,
//最小的长度扩增,为1,至少满足当前元素的插入需求
minCapacity - oldCapacity, /* minimum growth */
//理想扩容为原容量的1.5倍,这是首选的扩容大小
oldCapacity >> 1 /* preferred growth */);
//获取一个原数组的copy,其原数组的长度修改为新的容量
return elementData = Arrays.copyOf(elementData, newCapacity);
} else {
//如果原数组初始化时赋值为0
//为其赋值数组大小为DEFAULT_CAPACITY和minCapacity
//注意,主要原因是因为可能直接添加一个其他集合到ArrayList
//DEFAULT_CAPACITY == 10
return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
}
}
Vector
扩容机制
vector的扩容机制和ArrayList是类似的
- 如果是无参构造器创建的,设置默认容量为10
- 每次扩容为原容量的两倍。
源码
动态数组本质
Vector没有ArrayList的多种不同的空数组,处理比较简单粗暴,其实现动态数组的字段也是一个Object数组elementData
protected Object[] elementData;
构造器
有参构造器(携带初始容量)
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
//这个方法提供了指定capacityIncrement的途径
//capacityIncrement可以指定每次自动扩增的大小,如指定其为1,每次容量仅增加1
//默认的capacityIncrement为0,在这种情况下,每次增加的量为原本长度
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
无参构造器直接调用了有参构造器,并设置初始值为10,这是和ArrayList的一个主要区别
public Vector() {
this(10);
}
add方法
Vector的add实现和ArrayList几乎一致,当然,入口方法通过synchronized进行了锁保护。
public synchronized boolean add(E e) {
//集合修改次数++
modCount++;
//调用重载的add方法
add(e, elementData, elementCount);
return true;
}
private void add(E e, Object[] elementData, int s) {
//如果达到上限,进行扩容
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
elementCount = s + 1;
}
扩容
Vector的扩容机制没有分具体的初始化情况进行区分。具体内容与ArrayList仍然类似。
private Object[] grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = ArraysSupport.newLength(oldCapacity,
//最小增长值为新老容量之差,至少必须装下当前插入的值
minCapacity - oldCapacity, /* minimum growth */
//如果capacityIncrement>0,就采取用户设置的每次增长量
//如果等于0,就为默认的每次增加一倍(oldCapacity)
capacityIncrement > 0 ? capacityIncrement : oldCapacity
/* preferred growth */);
return elementData = Arrays.copyOf(elementData, newCapacity);
}