一、关于ArrayList的图如下图所示:
,WNA完全
从图中可以看出,ArrayList是List的一个典型实现,完全支持List接口的全部功能。
二、关于源码:
ArrayList构造函数:
成员方法解析:
1. public ArrayList(int initialCapacity)带参构造方法
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);
}
}
源码解析:
-
功能: 带参数构造函数,初始化数组的容量
-
源码思路:
- (1)判断传递进来的容量,容量值与0相比较,如果大于0,new一个Object类型的数组,将其赋给elementData
- (2)如果容量值等于0,说明想要初始化的数组容量为空,那直接将EMPTY_ELEMENTDATA赋给elementData
- (3)如果容量值小于0,则不符合题意,抛出异常
2. public ArrayList()空参构造方法
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
源码解析:
- 功能:初始化数组元素,因为没有参数,所以默认数组的元素个数为0,将DEFAULTCAPACITY_EMPTY_ELEMENTDATA赋给elementData
3. public ArrayList(Collection<? extends E> c)方法
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;
}
}
源码解析:
- 功能: 初始化ArrayList元素,使用已知传递进来的元素进行初始化
- 源码思路:
- (1)调用Collection类型形式参数c的toArray方法,将集合元素编程数组元素,存储在elementData中
- (2)将elementData数组的长度值赋给size,判断如果size的值不等于0,则再继续判断如果elementData数组的class值是否等于Object类型的数组的class,如果不相等,使用Arrays类的copyOf方法,给elementData数组赋初值
- (3)如果传递进来的集合元素为null,则将elementData数组赋为初始空数组EMPTY_ELEMENTDATA
4. public void trimToSize()方法
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
源码解析:
- 功能:修整此ArrayList实例的是列表的当前大小的容量。ArrayList所说没有用的值并不是null,而是ArrayList每次增长会申请多一点的空间,增长1.5倍+1,而不是两倍这样就会出现当size()= 1000的时候,ArrayList已经申请了1200空间的情况trimToSize 的作用只是去掉预留元素位置,就是删除多余的200,改为只申请1000,内存紧张的时候会用到 。
- 源码思路:
- 修改的方式是通过调用Arrays类的copyOf方法
5. public void ensureCapacity(int minCapacity)方法
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
? 0 : DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
源码解析:
-
功能:如果需要,增加此ArrayList实例的容量,以确保它至少可以容纳由最小容量参数指定的元素数。
-
源码思路:
-
(1)任何一个ArrayList对象都有一个capacity属性,用来指示该ArrayList的最小容量,即数组的“容纳能力”,我们知道ArrayList的内部是采用数组来存储元素的,由于Java数组是定长的,所以这个数组的大小一定是固定的,这个大小就是capacity。我们可以肯定capacity一定是大于或者等于ArrayList的size,那么当size不断增加到了要超过capacity的时候,ArrayList就不得不重新创建新的capacity来容纳更多的元素,这时需要首先建立一个更长的数组,将原来的数组中的元素赋值到新数组中,再删除原来的数组。因此当ArrayList越来越大时,这种操作的消耗也就越来越大。
-
(2)为了减少这种不必要的重建capacity操作,当我们能肯定ArrayList大致有多大时,我们可以先让ArrayList把capacity设为我们期望的大小,以避免多余的数组重建
-
(3)建设ArrayList自动把capacity设为10,每次重建时将长度递增原来的三分之二,那么当我们需要大约存储50个元素到ArrayList中时,就会大约需要重建数组4次,分别在增加第11、第17、第26、第39个元素的时候进行。如果我们一开始就让ArrayList的capacity为50,那么不需要任何数组重建就能完成所有插入操作了。
-
(4)Java允许我们在构造ArrayList的同时指定capacity,如new
ArrayList(50),也允许在以后将它设得更大,而增大capacity就是使用ensureCapacity()方法。注意:capacity只能比原来的更大,不能比原来的更小,否则Java会忽略该操作。ArrayList的初始默认capacity为10,所以给capacity指定小于10的整数毫无意义。 -
(5)ArrayList的size一定小于等于capacity,而且更重要的是,访问超过size的位置将抛出异常,尽管这个位置可能没有超过capacity。ensureCapacity()只可能增加capacity,而不会对size有任何影响。要增加size,只能用add()方法。
-
6. private static int calculateCapacity(Object[] elementData, int minCapacity)方法
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
源码解析:
- 功能:计算最小容量
- 源码思路:
- (1)判断如果elementData的值等于默认空数组的值,那么返回DEFAULT_CAPACITY和minCapacity中的最大值
- (2)如果elementData的值不等于默认空数组的值,则返回minCapacity值
7. private void ensureCapacityInternal(int minCapacity)方法
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
源码解析:
- 功能:扩容入口方法
8. private void ensureExplicitCapacity(int minCapacity)方法
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
源码解析:
- 功能:判断是否需要扩容
- 源码思路:
- 首先要更改modCount的值
- 如果最小需要空间比当前的elementData的长度大,则需要扩容,调用grow扩容方法,将minCapacity传递进去
9. private void grow(int minCapacity)方法
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
源码解析:
- 功能:动态扩容
- 源码思路:
- (1)定义一个变量oldCapacity,其值等于ArrayList中elementData数组的长度
- (2)定义一个变量newCapacity,其值等于ArrayList中elementData数组长度的1.5倍
- (3)如果新数组的容量小于预留的数组空间,就可以直接使用这个长度新建数组
- (4)如果新数组的容量大于预留的数组空间,就将预留数组长度设置为需要的长度
- (5)MAX_ARRAY_SIZE
值等于Java中int的最大值。下面要判断有没有超过最大限制,如果没有,就执行下一步,如果超过最大限制,需要修改最大限制 - (6)调用Arrays的copyOf方法将elementData数组指向新的内存空间newCapacity,并将elementData数组中的值传递到新的内存空间中
10. private static int hugeCapacity(int minCapacity) 方法
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
源码解析:
- 功能:数组能够容纳的最大数据元素个数
- 源码思路:
- (1)如果数组能够容纳数据的能力小于0,说明minCapacity是错误的,因此抛出异常
- (2)如果minCapacity的值大于数组的size,则返回整数的最大值,否则返回数组的size
11. public int size()方法
public int size() {
return size;
}
源码解析:
- 功能:获取数组的size大小
12. public boolean isEmpty()方法
public boolean isEmpty() {
return size == 0;
}
源码解析:
- 功能:判断数组中是否有元素
- 源码思路:
- 判断size的值是否为0
13. public boolean contains(Object o)方法、
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
源码解析:
- 功能:判断一个元素是否存在在数组中
- 源码思路:
- 通过调用indexOf方法来实现该功能
14. public int indexOf(Object o)方法
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; }
源码解析:
- 功能:从左到右判断元素是否在数组中,如果在,则返回元素的下标,如果不在返回-1,直到找到或者到数组末尾为止
- 源码思路:
- 分两种情况进行判断,一种是元素是null,另一种是元素非空
- 当元素是null时,通过for循环遍历数组,当找到数组中元素==null则返回元素下标i
- 当元素是非空时,通过for循环遍历数组,通过equals方法来判断数组中是否存在想找的元素
15. public int lastIndexOf(Object o)方法
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; }
源码解析:
- 功能:从右往左判断是否有元素o,如果有则返回元素的下标,否则返回-1
- 源码思路:
- 与indexOf方法相反
16. public Object clone()方法
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); } }
源码解析:
- 功能:克隆
- 源码思路:
- (1)调用super.clone
- (2)将elementData中的元素克隆到新的elementData中
- (3)将新的集合的modCount 值设置为0
17. public Object[] toArray()方法
public Object[] toArray() { return Arrays.copyOf(elementData, size); }
源码解析:
- 功能:将集合元素变为Object类型的数组返回
- 源码思路:
- 实现的方式是通过Arrays类的copyOf方法实现
18. public T[] toArray(T[] a)方法
public <T> T[] toArray(T[] a) { if (a.length < size) return (T[]) Arrays.copyOf(elementData, size, a.getClass()); System.arraycopy(elementData, 0, a, 0, size); if (a.length > size) a[size] = null; return a; }
源码解析:
- 功能:将集合中的元素转换为泛型类型的数组,存储在参数中返回
- 源码思路:
- (1)如果返回的参数a的数组长度小于集合的size,说明参数不能够存储下集合中的元素,直接通过调用Arrays类的copyOf方法,将调用结果返回
- (2)如果参数a的数组长度大于集合的size,说明参数能够存储下集合中的元素,调用System类的arraycopy方法将集合中的元素放在数组中,因为a的存储空间有多余的部分,需要最后将下标为size的元素置为null,最后返回a
19. E elementData(int index)方法
E elementData(int index) { return (E) elementData[index]; }
源码解析:
- 功能:返回elementData数组下标为index的元素值,get方法的基础方法
- 源码思路:
- 因为elementData本身是数组,所以想返回下标index的元素值,直接利用数组的elementData[index]即可
20. public E get(int index)方法
public E get(int index) { rangeCheck(index); return elementData(index); }
源码解析:
- 功能:返回集合中下标为index的元素
- 源码思路:
- 首先调用rangeCheck方法判断index是否符合题意
- 返回调用elementData方法的结果
21. public E set(int index, E element)方法
public E set(int index, E element) { rangeCheck(index); E oldValue = elementData(index); elementData[index] = element; return oldValue; }
源码解析:
- 功能:将集合中下标为index的元素值换为element
- 源码思路:
- (1)首先调用rangeCheck方法判断index下标是否符合条件
- (2)调用elementData方法获取下标为index的元素值,将该值放在oldValue中
- (3)将element值赋给elementData[index]中
- (4)将旧值返回
22. public boolean add(E e)方法
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
源码解析:
- 功能: 将元素e添加到集合中
- 源码思路:
- (1)首先调用ensureCapacityInternal方法,扩充数组的容量
- (2)将将e的值添加到elementData数组中
23. public void 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++; }
源码解析:
- 功能:向数组下标为index的位置,插入元素element
- 源码思路:
- (1)首先调用rangeCheckForAdd方法,判断index是否符合条件
- (2)调用ensureCapacityInternal方法,扩充数组的容量
- (3)将数组中index处及其后面的值向后移动1位
- (4)将element的值赋值给elementData数组的index下标位置
- (5)增加size的大小
24. public E remove(int index)方法
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; }
源码解析:
- 功能:将下标为index位置的元素移除
- 源码思路:
- (1)首先调用rangeCheck方法,用来判断index是否符合条件
- (2)更改modCount的值
- (3)调用elementData方法,获取index位置的元素值,放在oldValue变量中
- (4)定义变量numMoved,其值等于size - index - 1,即将第index+1个元素及其后面的元素向前移动
- (5)将最后一个元素赋值为null
- (6)返回删除的元素的信息
25. public boolean remove(Object o)方法
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; }
源码解析:
- 功能:从左向右一次遍历,将第一次出现的元素o从集合中删除
- 源码思路:
- 分两种情况进行判断,一种是o为null,另一种是o非null
26. private void fastRemove(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 }
源码解析:
- 功能:将第index元素从集合中删除
- 源码思路:
- (1)首先更改modCount值,因为每从结构上修改一次集合,就要将modCount的值加1
- (2)定义一个变量numMoved,其值等于将要移动的元素的个数
- (3)利用System类的arraycopy方法将第index+1及其后面的元素向前移动一位,即将第index元素覆盖(注意:是直接将index位置的元素覆盖,而不是返回其元素)
- (4)将集合最后一个元素赋为null
27. public void clear()方法
public void clear() { modCount++; // clear to let GC do its work for (int i = 0; i < size; i++) elementData[i] = null; size = 0; }
源码解析:
- 功能:将集合中的元素全部删除
- 源码思路:
- (1)首先修改modCount的值
- (2)利用for循环将集合中的元素全部置于null
- (3)将size的值置为0
28. public boolean addAll(Collection<? extends E> 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; }
源码解析:
- 功能:将集合中的元素添加到现有的集合中
- 源码思路:
- (1)定义一个Object类型的数组a,将集合c调用toArray方法,将集合c转换为数组,放在a中
- (2)定义一个变量numNew,用来存储数组a的长度
- (3)调用ensureCapacityInternal方法,扩充modCount
- (4)调用System类的arraycopy方法,将数组a中的元素copy到elementData中,数组a从下标0开始复制,复制到elementData中的下标size位置,复制numNew个元素
- (5)最后更改size的值
29. public boolean addAll(int index, Collection<? extends E> 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) System.arraycopy(elementData, index, elementData, index + numNew, numMoved); System.arraycopy(a, 0, elementData, index, numNew); size += numNew; return numNew != 0; }
源码解析:
- 功能:将集合中的元素添加到现有的集合中,增加一个添加的下标位置
- 源码思路:
- 与弟28个函数是相似的
30. protected void removeRange(int fromIndex, int toIndex)方法
protected void removeRange(int fromIndex, int toIndex) { modCount++; int numMoved = size - toIndex; System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved); // clear to let GC do its work int newSize = size - (toIndex-fromIndex); for (int i = newSize; i < size; i++) { elementData[i] = null; } size = newSize; }
源码解析:
- 功能:将集合中的元素从下标fromIndex开始到下标toIndex移除
- 源码思路:
- (1)更改modCount的值,将该值自增1
- (2)定义变量numMoved,该变量的值等于size - toIndex
- (3)调用System类的arraycopy方法,将elementData数组中位置toIndex的值及其后面的值复制到elementData数组的fromIndex位置
- (4)记着将newSize以后的值置为null
- (5)更改size的值
31. private void rangeCheck(int index)方法
private void rangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
源码解析:
- 功能: 判断index是否符合条件
- 源码思路:
- 如果index的值大于等于size的值,即下标的值大于数组的最大值,要抛出异常
32. private void rangeCheckForAdd(int index)方法
private void rangeCheckForAdd(int index) { if (index > size || index < 0) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
源码解析:
- 功能:判断将要插入的元素的位置是否符合条件
- 源码思路:
- 插入的元素位置需要小于size大于0才符合条件,否则抛出异常
33. private String outOfBoundsMsg(int index)方法
private String outOfBoundsMsg(int index) { return "Index: "+index+", Size: "+size; }
源码解析:
- 功能:抛出异常时返回的出错信息
- 源码思路:
- 返回元素的位置和集合的大小
34. public boolean removeAll(Collection<?> c)方法
public boolean removeAll(Collection<?> c) { Objects.requireNonNull(c); return batchRemove(c, false); }
源码解析:
- 功能:移除当前集合中集合c中所有元素
- 源码思路:
- (1)首先调用Objects类的requireNoNull方法,该方法用来判断c是否为null,如果为null则抛出异常,如果不为空,则返回c本身
- (2)移除的操作是调用batchRemove方法实现
35. public boolean retainAll(Collection<?> c)方法
public boolean retainAll(Collection<?> c) { Objects.requireNonNull(c); return batchRemove(c, true); }
源码解析:
- 功能:保留当前集合中所有集合c中的元素
- 源码思路:
- (1)调用Objects类的requireNonNull方法,判断c是否为空
- (2)调用batchRemove方法来实现保存操作
36. private boolean batchRemove(Collection<?> c, boolean complement)方法
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; }
源码解析:
- 功能:批量删除元素,利用complement来判断是删除参数c中的元素,还是保留c中的元素。complement为true,则保留c中的元素,为false则删除c中的元素
- 源码思路:
- (1)定义一个Object类型的数组elementData,将当前集合的elementData值赋值给新定义的elementData
- (2)通过for循环来修改当前集合中的元素信息,如果c中不包含elementData[r]这个元素,则直接将r位置的元素赋值给w位置的元素,w自增
- (3)在finally中,防止抛出异常导致上面r的右移过程没完成 , 将r未右移完成的位置的元素赋值给w右边位置的元素 ,修改w值增加size-r
- (4)如果w不等于size,说明有被覆盖掉的元素,则将w后面的元素都赋值为null ,最后修改size的值
37. public ListIterator listIterator(int index)方法
public ListIterator<E> listIterator(int index) { if (index < 0 || index > size) throw new IndexOutOfBoundsException("Index: "+index); return new ListItr(index); }
源码解析:
- 功能:创建ArrayList的迭代器,迭代器有起始位置
- 源码思路:
- (1)首先判断index值是否符合条件,如果不符合条件则抛出异常
- (2)如果符合条件,new一个ListItr,将index值作为参数传递进去,迭代器初始位置为index
38. public ListIterator listIterator()方法
public ListIterator<E> listIterator() { return new ListItr(0); }
源码解析:
- 功能:创建ArrayList的迭代器,迭代器没有起始位置
- 源码思路:
- 直接返回ListItr,迭代器初始位置为0
39. public Iterator iterator()方法
public Iterator<E> iterator() { return new Itr(); }
源码解析:
- 功能:重写父类的iterator方法