类声明:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
public interface RandomAccess {}
这个接口是一个标记接口,表明其支持快速的随机访问,也就是通过索引下标能否快速的移动到对应的元素上.主要是允许通过算法来更改其的行为,从而在将其应用到随机或连续访问列表时能提供良好的性能。
在程序遍历的时候很多情况下不知道是使用for还是foreach或iterator。
在更多的时候都是选择比较简略的foreach()或则for,其实遍历方式的选择与遍历效率有明显联系
而对一个实现 RandomAccess 接口的list而言,使用for()循环,遍历效率比另外两种都要高不少
在判断一个list选择何种方式遍历时,我们可以这样:
if (list instanceof RandomAccess) {
for(int m = 0; m < list.size(); m++){}
}else{
Iterator iter = list.iterator();
while(iter.hasNext()){}
}
成员变量
private static final long serialVersionUID = 8683452581122892189L;
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
*默认的elementData,当使用无参构造器时会将此数组实例对象的引用给elementData
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
内部容器--储存元素
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* The size of the ArrayList (the number of elements it contains).
*当前的大小
* @serial
*/
private int size;
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
ArrayList添加一个元素
/**
* Appends the specified element to the end of this list.
*/
public boolean add(E e) {
//判断是否扩容和扩容操作,确保添加新元素后容量足够
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
//保证添加元素之后数组容量在范围之内
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//如果使用无参构造器得到arraylist实例,没有指定初始容量
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
//minCapacity:最小的扩容值--当前数组的长度小于minCapacity则扩容
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*扩充这个数组的容量确保他能够容下最小容量参数所指定的元素
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);//新的数组的容量 = 数组的容量 + 数组的容量/2
if (newCapacity - minCapacity < 0)//保证新的数组的大小一定比原数组的大小大
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)//如果新的数组的大小超过array的最大的大小(maximum size of array),进行最后的扩容+8
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
//如果复制数组_关于复制数组的几种方式的效率_参考:http://blog.csdn.net/tingzhiyi/article/details/52344845
elementData = Arrays.copyOf(elementData, newCapacity);
//Arrays.copyOf--实际调用的是system的System.arraycopy(...)方法属于浅复制,使用的时候需要注意
---------------------------------------------------------------------------------------------------------
List<Object> list = new ArrayList<>();
//分别为list增加一个对象和一个string
list.add(new TestOne()); //TestOne是一个class
list.add("aaa");
Object [] ss = list.toArray();//list.toArray()也是由system的System.arraycopy(...)方法实现
//改变新的数组的值
((TestOne)ss[0]).setA("aa");
((TestOne)ss[0]).setA1(4);
System.out.println(list.toString());
ss[1] = "bbb";
System.out.println(ss[0].toString()+":"+ss[1].toString());
System.out.println(list.get(0)==ss[0]);
System.out.println(list.get(1)==ss[1]);
result://复制并不会新增堆中的实例对象,只有新增一个指向该实例的一个引用
[TestOne [a=aa, a1=4], aaa]
TestOne [a=aa, a1=4]:;;;bbb
true
false
---------------------------------------------------------------------
}
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的clone方法
/**
* Returns a shallow copy of this <tt>ArrayList</tt> instance. (The
* elements themselves are not copied.)
返回这个ArrayList实例的浅拷贝————其元素本身不被复制,即复制引用_
想要其实现深拷贝只需在其涉及的所有引用类型的引用的类
都实现java.lang.Cloneable接口和都重写java.lang.Object.clone()方法
在clone方法中调用super.clone()返回
或对象序列化和反序列化实现深拷贝
* @return a clone of this <tt>ArrayList</tt> instance
*/
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);
}
}
-------------------------------------------------------------------------------------
List<Object> list = new ArrayList<>();
list.add(new TestOne());
list.add("aaa");
List<Object> list22 = (List<Object>) ((ArrayList)list).clone();
((TestOne) list22.get(0)).setA("bb");
((TestOne) list22.get(0)).setA1(5);
list22.set(1, 8);
System.out.println(list22.get(0)==list.get(0));
System.out.println(list22.get(1)==list.get(1));
=====>
true
false
ArrayList的remove方法
/** 根据索引删除元素
* Removes the element at the specified position in this list.
* Shifts any subsequent elements to the left (subtracts one from their
* indices).
将数组此索引的后面的元素直接复制到索引开始位置到结束(后面的元素都左移一位),然后将最后面的元素置null方便GC
* @param index the index of the element to be removed
* @return the element that was removed from the list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
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//数组的元素个数减一,length不变
return oldValue; //返回删除的元素的值
}
/** 根据value删除第一个出现的元素,如果此value不存在则不改变
*/
public boolean remove(Object o) {
//equals调用则不能为null
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;
}
//此方法与remove(int index)类似,没有返回值
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
}
注意:每次删除一个元素,其size都会减1,那么循环删除多个arraylist元素的时候不能单纯的使用size
如: for(int i = 0; i < list.size();i++){
//.....
list.remove(i);
}
在remove一条信息时,
ArrayList的大小已经改变(即list.size()已经改变);
在i大于等于list.size()时,循环跳出,后面的ArrayList不能再执行;
所以必须在remove的同时,执行i--,即i=i-1;
现在才能遍历所有List中的信息。也不能在用Iterator遍历时使用remove,会抛异常。
/**
* 清空:将储存数组的value全部置null
*/
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
ArrayList的sublist方法
/**
* Returns a view of the portion of this list between the specified
* {@code fromIndex}, inclusive, and {@code toIndex}, exclusive. (If
* {@code fromIndex} and {@code toIndex} are equal, the returned list is
* empty.) The returned list is backed by this list, so non-structural
* changes in the returned list are reflected in this list, and vice-versa.
* The returned list supports all of the optional list operations.
*返回list的一部分视图,如果开始位置和结束位置一样则返回空的list,
返回的list没有结构,仅仅是目标list的一部分,两个一体,改变一个另一个也会改变
返回的list支持list所有的操作
* <p>This method eliminates the need for explicit range operations (of
* the sort that commonly exist for arrays). Any operation that expects
* a list can be used as a range operation by passing a subList view
* instead of a whole list. For example, the following idiom
* removes a range of elements from a list:
* <pre>
* list.subList(from, to).clear();
* </pre>
* @throws IndexOutOfBoundsException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
*/
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);//一个范围检查
return new SubList(this, 0, fromIndex, toIndex);
}
//SubList 是arrayList的一个私有的内部类,其内部对list的操作都是在外部类的elementdata上进行的
private class SubList extends AbstractList<E> implements RandomAccess {
private final AbstractList<E> parent;//表示它的外部类的引用
private final int parentOffset;//索引开始位置—不需要记录索引的结束位置,可size可以表示索引的结束位置
private final int offset;//当前索引位置—
int size;//记录此视图元素的数量
SubList(AbstractList<E> parent,
int offset, int fromIndex, int toIndex) {
this.parent = parent;
this.parentOffset = fromIndex;
this.offset = offset + fromIndex;
this.size = toIndex - fromIndex;
this.modCount = ArrayList.this.modCount;
}
}