由上图可知:
ArrayList
实现了List
、 RandomAccess
、Cloneable
、java.io.Serializable
接口,
而List
继承了Collection
接口(Java可以多实现[implements],但只能单继承[extends])。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
//默认初始化容量
private static final int DEFAULT_CAPACITY = 10;
//空实例时的数组,经过remove或是clear等操作为空后的数据,或者代表初始化长度为0的数据时的数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//默认为空,ArrayList实例刚新建不传参时使用的数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//用来存储ArrayList数据的数组,ArrayList的容量就是这个数据的length
transient Object[] elementData;
//ArrayList的大小,即elementData对象的length
private int size;
//传参必须大于等于0 ,EMPTY_ELEMENTDATA 在此处使用
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {//容量为0
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
//刚新建ArrayList时,会默认使用空数组 DEFAULTCAPACITY_EMPTY_ELEMENTDATA在此处使用
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
}
使用transient
修饰elementData
数组,可以防止被自动序列化。
1、在末尾添加数据
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 动态扩容,在未添加任何数据之前,初始状态的size默认值是0
elementData[size++] = e; //在数组末尾添加元素
return true;
}
下面来看看如何动态扩容的:
//如果数据elementData 数组为原始空数组,将容量扩充为默认容量大小10,或者是传入进来的minCapacity,
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); //选取默认容量和传入进来的minCapacity中较大的一个来进行扩容
}
ensureExplicitCapacity(minCapacity);
}
protected transient int modCount = 0; //表示elementData被修改的次数
private void ensureExplicitCapacity(int minCapacity) {
modCount++; //全局变量,表示修改elementData的次数,初始值为0。每次动态改变数组elementData的大小,都会增加一次
//再次检查,防止elementData溢出
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//2147483647 - 8
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
//扩容elementData
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0) //容量超过数据最大值
newCapacity = hugeCapacity(minCapacity);
// copy数据并扩容
elementData = Arrays.copyOf(elementData, newCapacity);
}
//容量操作数据最大值的时候,就讲将容量扩大到2147483647 ,及 Integer.MAX_VALUE
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
2、在指定位置添加数据
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); //扩容
//调用native方法来填充数组,已不再java范畴
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
//检查数组是否越界
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
System
的arraycopy
方法如下,是个native
本地C
或C++
方法,已不再java讨论的范畴。
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
同样remove
也是调用的本地C
或C++
方法来实现的移除操作。
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// Write out size as capacity for behavioural compatibility with clone()
s.writeInt(size);
// Write out all elements in the proper order.
for (int i=0; iif (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
elementData = EMPTY_ELEMENTDATA; //置空
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in capacity
s.readInt(); // ignored
if (size > 0) {
// be like clone(), allocate array based upon size not capacity
ensureCapacityInternal(size);
Object[] a = elementData;
// Read in all elements in the proper order.
for (int i=0; i
当对象中自定义了 writeObject 和 readObject 方法时,JVM 会调用这两个自定义方法来实现序列化与反序列化。
从实现中可以看出 ArrayList 只序列化了被使用的数据。
由上图可知:
Vector 实现了List
、RandomAccess
、Cloneable
、java.io.Serializable
接口,
而List 继承了Collection接口(Java可以多实现[implements],但只能单继承[extends])。
Vector 也是实现于 List 接口,底层数据结构和 ArrayList 类似,也是一个动态数组存放数据。
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
protected Object[] elementData; //存储数据的数组
protected int elementCount; //Vector组件的长度
protected int capacityIncrement; //当elementData数组的数量增加到大于其容量时,就会扩充数组的容量,每次扩充这么大的量
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
public Vector(int initialCapacity) {
this(initialCapacity, 0); //默认扩充量capacityIncrement 为0
}
public Vector() {
this(10); //默认的数组长度也是10,和ArrayList一样
}
}
1、在末尾添加数据
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
private void ensureCapacityHelper(int minCapacity) {
// 防止溢出
if (minCapacity - elementData.length > 0)
grow(minCapacity);//动态扩容
}
//如果设置了capacityIncrement 值,就扩容capacityIncrement 的量,否者就扩容到elementData.length的两倍
//当然 这里只add方法只扩容了1个单位
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); //底层还是用的 System.arraycopy 方法实现复制数组,arraycopy 是一个native方法,已不是java范畴
}
//2147483647 - 8
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
//若是elementData到达数组最大长度,就让其值扩充为Integer.MAX_VALUE
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
与ArrayList
相比,Vector
的 add()
方法的时候使用 synchronized
进行同步写数据,但是开销较大,所以 Vector
是一个同步容器并不是一个并发容器。
2、在指定位置添加数据
public void add(int index, E element) {
insertElementAt(element, index);
}
//可见底层还是调用的 System.arraycopy C或C++方法来实现的数组复制
public synchronized void insertElementAt(E obj, int index) {
modCount++;
if (index > elementCount) {
throw new ArrayIndexOutOfBoundsException(index
+ " > " + elementCount);
}
ensureCapacityHelper(elementCount + 1);
System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
elementData[index] = obj;
elementCount++;
}
//底层还是调用的 System.arraycopy C或C++方法来实现的数组复制
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;
}
同:ArrayList
和Vector
底层数据结构相同也是一个动态数组存放数据。都实现了List
、 RandomAccess
,、Cloneable
、java.io.Serializable
接口。
异:Vector
使用 synchronized
进行同步写数据,,所以 Vector 是一个同步容器并不是一个并发容器,但是开销较大。而ArrayList
是一个支持并发的容器。
ps: 文末推荐其他几篇有关集合的文章:
常用集合之ArrayList和Vector的区别源码浅析
常用集合之LinkedList源码浅析
常用集合之HashMap源码浅析
常用集合之HashSet源码浅析
常用集合之LinkedHashMap源码浅析