源码解析ArrayList和Vector
目录
ArrayList类的定义
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
...
}
ArrayList继承了AbstractList,实现了List、RandomAccess、Cloneable、Serializable接口。
实现了List接口,可以实现List的一些增、删、改、查等
实现了RandomAccess接口,表明可以被随机访问,可以通过下标来获取元素。
实现了Cloneable接口,表明可以被克隆
实现了Serializable表明可以被序列化
ArrayList的构造方法和属性
//默认的初始化容量
private static final int DEFAULT_CAPACITY = 10;
//默认的空数组,用来初始化空数组的时候使用
private static final Object[] EMPTY_ELEMENTDATA = {};
//默认构造函数里面的空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//保存ArrayList数据的对象数组缓冲区
transient Object[] elementData;
//集合的长度
private int size;
//带int参数的构造函数,如果传入的参数initialCapacity>0,则设置新建一个长度为initialCapacity的数组;
//如果等于0,则设置为空数组;小于0会抛出异常
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
//没有参数的构造方法,当第一次添加元素的时候扩容10
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//传入集合参数来初始化ArrayList
public ArrayList(Collection<? extends E> c) {
Object[] a = c.toArray(); //将集合转化成对象数组
if ((size = a.length) != 0) {
if (c.getClass() == ArrayList.class) {
elementData = a; //然后赋值给elementData
} else {
//如果c.toArray()出错,利用Arrays.copyOf来复制集合中的元素,然后给elementData
elementData = Arrays.copyOf(a, size, Object[].class);
}
} else {
// 如果集合中没有元素,则将EMPTY_ELEMENTDATA空数组赋值给elementData
elementData = EMPTY_ELEMENTDATA;
}
}
ArrayList的添加元素方法
add(E e)方法
public boolean add(E e) {
modCount++; //操作计数
add(e, elementData, size); //调用添加函数
return true;
}
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length) //判断elementData数组的长度和元素个数
elementData = grow(); //如果相等就扩容
elementData[s] = e; //在数组末尾添加元素
size = s + 1; //修改size的值
}
private Object[] grow() {
return grow(size + 1);
}
private Object[] grow(int minCapacity) {
int oldCapacity = elementData.length;
if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
oldCapacity >> 1 /* preferred growth */);//默认扩容一半
return elementData = Arrays.copyOf(elementData, newCapacity);//构建扩容后的数组
} else {
return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
}
}
add(int index, E element)通过索引添加
public void add(int index, E element) {
rangeCheckForAdd(index);//判断是否越界,越界抛出异常
modCount++;
final int s;
Object[] elementData;
if ((s = size) == (elementData = this.elementData).length)//判定是否需要扩容
elementData = grow();
System.arraycopy(elementData, index,
elementData, index + 1,
s - index); //将index后面的数据向后移一位
elementData[index] = element; //将index索引位赋值
size = s + 1;
}
addAll(Collection<? extends E> c)
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();//将集合转化为数组对象
modCount++;
int numNew = a.length;
if (numNew == 0)
return false;
Object[] elementData;
final int s;
if (numNew > (elementData = this.elementData).length - (s = size))//判定是否扩容
elementData = grow(s + numNew);
System.arraycopy(a, 0, elementData, s, numNew);//复制数组完成批量赋值
size = s + numNew;
return true;
}
addAll(int index, Collection<? extends E> c)
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);//判定是否越界,越界抛出异常
Object[] a = c.toArray();//将集合转化为数组对象
modCount++;
int numNew = a.length;
if (numNew == 0)
return false;
Object[] elementData;
final int s;
if (numNew > (elementData = this.elementData).length - (s = size))//判定是否扩容
elementData = grow(s + numNew);
int numMoved = s - index;
if (numMoved > 0)
System.arraycopy(elementData, index,
elementData, index + numNew,
numMoved);//如果numMoved>0,将index后面的数据向后移动numNew步
System.arraycopy(a, 0, elementData, index, numNew);
size = s + numNew;
return true;
}
ArrayList的增加操作在添加之前,都会想判定是否扩容,如果扩容就会大量的复制数组,所以用System.arraycopy提高效率。
ArrayList删除元素方法
remove(int index)通过索引删除
public E remove(int index) {
Objects.checkIndex(index, size);
final Object[] es = elementData;
@SuppressWarnings("unchecked") E oldValue = (E) es[index];
fastRemove(es, index);
return oldValue;
}
private void fastRemove(Object[] es, int i) {
modCount++;
final int newSize;
//判定删除一个元素后,是否大于索引值i
if ((newSize = size - 1) > i)
//把i索引值后面的元素向前移一步
System.arraycopy(es, i + 1, es, i, newSize - i);
//避免内存泄漏
es[size = newSize] = null;
}
remove(Object o)按照对象删除
public boolean remove(Object o) {
final Object[] es = elementData;
final int size = this.size;
int i = 0;//首次出现元素的位置记录
//寻找要删除元素
found: {
if (o == null) {
for (; i < size; i++)
if (es[i] == null)
break found;
} else {
for (; i < size; i++)
if (o.equals(es[i]))
break found;
}
//如果没找到就返回false
return false;
}
//找到后就按照索引删除
fastRemove(es, i);
return true;
}
ArrayList更改元素的值
set(int index, E element)
public E set(int index, E element) {
Objects.checkIndex(index, size);//越界检查
E oldValue = elementData(index);//拿出元素
elementData[index] = element;//覆盖元素
return oldValue;//返回元素
}
ArrayList查看元素的值
get(int index)
public E get(int index) {
Objects.checkIndex(index, size);//越界检查
return elementData(index);//通过下标取出数据
}
E elementData(int index) {
return (E) elementData[index];
}
ArrayList小结:
- ArrayList的底层是数组实现的,长度是动态的增加
- 扩容的长度是原来的长度的一半
- 实现了RandomAccess接口,使得读取数据很容易
- 添加和删除操作会大量的复制数组,性能较差
- ArrayList的方法没有synchronized修饰或者加锁,所以线程是不安全的
ArrayList和Vector的区别
区别主要有两个:
- 扩容的数量不一样
- Vector的线程有synchronized修饰,所以线程是安全的
首先看下Vector扩容的源码
private Object[] grow() {
return grow(elementCount + 1);
}
private Object[] grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
//如果容量增量capacityIncrement大于0,则扩容增加capacityIncrement;如果小于或者等于0,则翻倍原来的长度
capacityIncrement > 0 ? capacityIncrement : oldCapacity
/* preferred growth */);
return elementData = Arrays.copyOf(elementData, newCapacity);
}
看一下一些基本的函数源码
//添加
public synchronized boolean add(E e) {
modCount++;
add(e, elementData, elementCount);
return true;
}
//删除
public synchronized E remove(int index) {
modCount++;
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
E oldValue = elementData(index);
int numMoved = elementCount - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--elementCount] = null; // Let gc do its work
return oldValue;
}
//修改
public synchronized E set(int index, E element) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
//查询
public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
可以看到这些基本的方法都是synchronized修饰的,所以是线程同步的。