ArrayList简介
- ArrayList是Java语言中常用的集合,他的底层由数组实现,因此继承了数据数据结构的优点:查询效率高(时间复杂度O(1)),插入删除慢(时间复杂度O(N))。
- ArrayList的构造方法中可以设置容器初始化容量大小,默认容量长度为10,当ArrayList到达容量阈值之后,会进行每次0.5倍的扩容。
附ArrayList源码如下:
成员变量
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
/* 默认容量长度 10*/
private static final int DEFAULT_CAPACITY = 10;
/* 没有数据的空数组*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/* 集合初始化时没有给长度,使用默认长度(10)的数组 */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/*transient 修饰的变量 实际的数据数组*/
transient Object[] elementData; // non-private to simplify nested class access
/* 集合长度成员变量*/
private int size;
构造函数
/*带有长度的集合初始化*/
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;
}
/*Collection 集合构造方式,直接将集合转给数组,复制给全局保存数据数组*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
集合扩容
/* 扩容方法,判断当前容量数据是否为默认长度数组,是0,否10,作用是传入小于默认容量的数字时,不进行扩容缩容*/
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
/*扩容,如果当前容量数据就是默认长度数组,则取传入长度数值与默认长度数据最大的长度,进行扩容.*/
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
/*扩容,包含记录集合容量变化次数操作(modCount++),传入长度超过当前容量长度进行扩容 */
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/* 数租最大长度为2^31-9*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* 实际扩容方法,每次扩容为原来的1.5倍,如果扩容后长度还是小于需要扩容的长度,以实际长度扩容
* 实际扩容超过数租最大长度实际扩容为Integer.MAX_VALUE长度,然后复制到当前数据容量数组中,这个操作有 *可能引起虚拟机内存相关问题
*/
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);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
/*超过默认数组最大长度,返回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;
}
核心方法
/*将当前容量值设置为当前元素实际大小,size:元素实际大小,elementData.length当前容量值*/
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
/* 返回集合数据长度,注意不是容量长度, */
public int size() {
return size;
}
/*判断是否为空,显示编码用长度和0进行判断也是可以的(注意空指针) */
public boolean isEmpty() {
return size == 0;
}
/* 是否包含某元素,实际调用的是indexOf方法 */
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
/*返回某元素在集合中的第一个元素索引位置*/
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
/*返回某元素在集合中最后一个元素索引位置*/
public int lastIndexOf(Object o) {
if (o == null) {
for (int i = size-1; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
/*返回ArrayList的浅拷贝*/
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
/*集合转数组,注意size数据实际数目*/
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
/*集合转指定类型数组*/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
/*获得当前索引对象,类中操作*/
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
/*获得某索引的对象,对外方法*/
public E get(int index) {
//判断是否索引越界(获取索引大于集合实际数据个数)
rangeCheck(index);
return elementData(index);
}
/*给某索引设置值*/
public E set(int index, E element) {
//判断时候索引越界(获取索引大于集合实际数据个数),注意:增加的话用add()方法,这里只能设置索引为0--size位置的值
rangeCheck(index);
//获取原来值
E oldValue = elementData(index);
//设置
elementData[index] = element;
//返回原来值
return oldValue;
}
/*
*向集合中添加元素,感觉add方法很耗性能,每次调用都会进行扩容判断,不够就进行扩容
* 所以创建集合对象时 可以预估长度就给上长度
*/
public boolean add(E e) {
//扩容,保证有空间减价元素
ensureCapacityInternal(size + 1); // Increments modCount!!
//设置值
elementData[size++] = e;
//返回状态
return true;
}
/*想某个索引中添加元素,这种方法利用于创建是已经给了长度或者想0-9索引中添加元素*/
public void add(int index, E element) {
//判断索引是否合法
rangeCheckForAdd(index);
//判断是否需要扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
//复制元素
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
//设置
elementData[index] = element;
//个数值自增
size++;
}
/*删除元素,返回要删除索引值*/
public E remove(int index) {
//索引合法判断
rangeCheck(index);
//集合数据数组结构变化次数加1
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;
}
/*删除元素,返回删除成功与否状态,只删除第一个比配的元素 */
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
/* 删除元素时调用的方法*/
private void fastRemove(int index) {
modCount++;
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
}
/*集合清空*/
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
/*按照c的迭代器所返回的元素顺序,将c中的所有元素添加到此列表的尾部*/
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
/*从指定位置index开始,将指定c中的所有元素插入到此列表中*/
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
int numMoved = size - index;
if (numMoved > 0)
//先将ArrayList中从index开始的numMoved个元素移动到起始位置为index+numNew的后面去
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
//再将c中的numNew个元素复制到起始位置为index的存储空间中去
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
/*删除fromIndex到toIndex之间的全部元素 */
protected void removeRange(int fromIndex, int toIndex)
{
modCount++;
//numMoved为删除索引后面的元素个数
int numMoved = size - toIndex;
//将删除索引后面的元素复制到以fromIndex为起始位置的存储空间中去
System.arraycopy(elementData, toIndex, elementData, fromIndex,numMoved);
int newSize = size - (toIndex-fromIndex);
//将ArrayList后面(toIndex-fromIndex)个元素置为null
for (int i = newSize; i < size; i++)
{
elementData[i] = null;
}
size = newSize;
}
/* 检查索引是否越界 */
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
/*判断索引是否合法*/
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
/*拼接MSG*/
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
/* 删除全部,删除ArrayList中包含在c中的元素*/
public boolean removeAll(Collection<?> c) {
//检查是否为空
Objects.requireNonNull(c);
//删除
return batchRemove(c, false);
}
/*返回交集*/
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, true);
}
/*删除方法*/
private boolean batchRemove(Collection<?> c, boolean complement) {
final Object[] elementData = this.elementData;
int r = 0, w = 0;
boolean modified = false;
try {
for (; r < size; r++)
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];
} finally {
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
if (r != size) {
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
if (w != size) {
// clear to let GC do its work
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
/* 将ArrayList的“容量,所有的元素值”都写入到输出流中 */
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
//写入数组大小
s.writeInt(size);
//写入所有数组的元素
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
/* 先将ArrayList的“大小”读出,然后将“所有的元素值”读出 */
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<size; i++) {
a[i] = s.readObject();
}
}
}