定义
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
底层实现:数组
- AbstractList 实现List的基本操作
- List 定义List的基本方法
- RandomAccess 一种标志位,类似于clone标志,作用:
JDK中说的很清楚,在对List特别是Huge size的List的遍历算法中,要尽量来判断是属于RandomAccess(如ArrayList)还是Sequence List (如LinkedList),因为适合RandomAccess List的遍历算法,用在Sequence List上就差别很大,常用的作法就是:
要作一个判断:
if (list instance of RandomAccess) {
for(int m = 0; m < list.size(); m++){}
}else{
Iterator iter = list.iterator();
while(iter.hasNext()){}
}
参考这里
属性
private transient Object[] elementData;
transient :此字段是否可以被序列化
elementData : ArrayList底层实现数组,初始大小10
方法
trimToSize
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = Arrays.copyOf(elementData, size);
}
}
作用:重新定义数组初始化大小
modCount:list被改变次数,定义在iterator中,用以判断list是否被同步修改,所以ArrayList不是同步安全的,可以使用以下代码包装一次list使其成为同步安全的:
List list = Collections.synchronizedList(new ArrayList(...));
/**
* The modCount value that the iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
int expectedModCount = modCount;
若两者不相等抛出ConcurrentModificationException异常
重新定义数组大小,只是用来定义数组的容量,不代表数组中有多少个元素,所以
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
用以上方法初始化ArrayList不能初始化ArrayList大小,一般用来当ArrayList数据较大时使用,避免ArrayList底层数组替换。
add(E e)
在list末尾添加元素
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
ensureCapacityInternal:判断是否需要扩容并扩容,modCount自增1
elementData[size++] = e; 新增元素加入数组
扩容方法:
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);
}
扩容:newCapacity = oldCapacity + (oldCapacity >> 1) 一次扩容一半,至于为什么每次扩容1.5倍,效率问题,扩容之后并将源数据copy到新数组中。
add(int index, E element)
在指定位置添加元素
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++;
}
rangeCheckForAdd: 检查下标是否越界
System.arraycopy:将数组中index至末尾数据右移,耗时
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
将数组src中以srcPos开始长度为length的数据复制到dest中,从destPos开始粘贴;
余下add方法都是以以上两种方法为基础
contains(Object o)
数组中是否包含o,正序查找
indexOf(Object o)
返回list中第一次出现o的下标,正序查找,无返回-1。
lastIndexOf(Object o)
返回list从末尾第一次出现o的下标,逆序查找,无返回-1。
clone()
public Object clone() {
try {
@SuppressWarnings("unchecked")
ArrayList<E> v = (ArrayList<E>) 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();
}
}
ArrayList的clone属于浅拷贝,从这句v.elementData = Arrays.copyOf(elementData, size);
ArrayList的clone只是将原数组中数据的地址复制到新数组中