1、简述
ArrayList底层的实现是使用了数组保存所有的数据,所有的操作本质上是对数组的操作,每一个ArrayList实例都有一个默认的容量(数组的大小,默认是10),随着
对ArrayList不断增加元素,默认的数组会不断的向新数组进行拷贝,由于ArrayList的内部是通过对数组的操作实现的,所以它是线程不安全的
2、实现
a、构造方法:
AyyarList一共提供了三种构造方法:
/*** Constructs an empty list with the specified initial capacity.
*
*@paraminitialCapacity the initial capacity of the list
*@throwsIllegalArgumentException if the specified initial capacity
* is negative*/
public ArrayList(intinitialCapacity) {if (initialCapacity > 0) {this.elementData = newObject[initialCapacity];
}else if (initialCapacity == 0) {this.elementData =EMPTY_ELEMENTDATA;
}else{throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
}
}/*** Constructs an empty list with an initial capacity of ten.*/
publicArrayList() {this.elementData =DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}/*** Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
*@paramc the collection whose elements are to be placed into this list
*@throwsNullPointerException if the specified collection is null*/
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;
}
}
View Code
在jdk1.8中,ArrayList的无参构造方法默认的是创建了一个空的数组,只有当你第一次添加是时候才会设置它的默认长度为10 ,在jdk1.6中无参构造方法默认
的就是创建一个长度为10 的空数组
b、定义内部数组:
/*** The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.*/
transient Object[] elementData; //non-private to simplify nested class access
关于transient关键字的说明可以参考我的另外一篇博客 java学习笔记之对象序列化
3、ArrayList的操作
增加操作:
add(E e):
/*** Appends the specified element to the end of this list.
*
*@parame element to be appended to this list
*@returntrue (as specified by {@linkCollection#add})*/
public booleanadd(E e) {
ensureCapacityInternal(size+ 1); //Increments modCount!!
elementData[size++] =e;return true;
}
调用add(E e)方法时首先会调用ensureCapacityInternal(int minCapacity)去判断是否需要对集合进行扩容,然后默认的将新插入的对象放到内部数组的末尾,
当内部数组需要扩容时,每次直接将数组的长度值原来的两倍,这种操作的代价是很高的,所以在使用过程中我们尽量避免数组的扩容,当可以预知数组长度的时候
可以在构造的时候久指定其长度
add(int index, E element)
/*** Inserts the specified element at the specified position in this
* list. Shifts the element currently at that position (if any) and
* any subsequent elements to the right (adds one to their indices).
*
*@paramindex index at which the specified element is to be inserted
*@paramelement element to be inserted
*@throwsIndexOutOfBoundsException {@inheritDoc}*/
public void add(intindex, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size+ 1); //Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size-index);
elementData[index]=element;
size++;
}
在调用add(int index, E element)方法想ArrayList中插入一条数据时,这个方法内部先去判断传入的下表是否大于数组的长度。大于的话就会
抛出IndexOutOfBoundsException异常,插入的下表小于数组的长度的时候,再去判断数组是否需要扩容,最后再调用System.arraycopy方法将数组下表大于传入
的index的元素全部后移以为,并将插入的元素放到index位置
addAll(Collection extends E> c)
/*** Appends all of the elements in the specified collection to the end of
* this list, in the order that they are returned by the
* specified collection's Iterator. The behavior of this operation is
* undefined if the specified collection is modified while the operation
* is in progress. (This implies that the behavior of this call is
* undefined if the specified collection is this list, and this
* list is nonempty.)
*
*@paramc collection containing elements to be added to this list
*@returntrue if this list changed as a result of the call
*@throwsNullPointerException if the specified collection is null*/
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;
}
在调用addAll(Collection extends E> c) 插入一个集合时,这个方法内部先去判断增加这个集合数组是否需要扩容,然后调用
arraycopy(Object src, int srcPos,Object dest, int destPos,int length)方法将新增加的集合放到数组的末尾
更新操作:
public E set(intindex, E e) {
rangeCheck(index);
checkForComodification();
E oldValue= ArrayList.this.elementData(offset +index);
ArrayList.this.elementData[offset + index] =e;returnoldValue;
}
在调用set(int index,E e)方法修改里面的值时,方法内部先去检查index下表是都超过数组的最大长度,然后再检查是否有其他的线程对这个对象的长度
进行修改了(所以是线程不安全的,多线程同时操作容易直接抛异常),最后是直接替换数组中下表index对应的值
删除操作:
/*** Removes the element at the specified position in this list.
* Shifts any subsequent elements to the left (subtracts one from their
* indices).
*
*@paramindex the index of the element to be removed
*@returnthe element that was removed from the list
*@throwsIndexOutOfBoundsException {@inheritDoc}*/
public E remove(intindex) {
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
returnoldValue;
}
在调用remove(int index)删除ArrayList中的数据时,首先校验传入的下标index是大于数组的长度,然后取出将要被删除的数并判断下标index之后是否还有元素,
如果有的话将下标之后的元素全部往前移动一位,并最终将删除的元素的值返回