[Java代码] Java ArrayList源码分析

ArrayList介绍

List 接口的一个实现类,内部是用一个数组存储元素值,相当于一个可变大小的数组。

签名
  1. public class ArrayList<E>
  2. extends AbstractList<E>
  3. implements List<E>, RandomAccess, Cloneable, Serializable
  4. http://www.nvzi91.cn/fujianyan/29948.html
复制代码

可以看到ArrayList继承了AbstractList抽象类,它实现了List接口的大多数方法。如果要实现一个不可变的List,只要继承这个类并且实现get(int)和size方法。如果要实现可变的List,需要覆盖set(int, E)。另外,如果List的大小是可变的,还要覆盖add(int, E)和remove()方法。

构造器

ArrayList提供了三个构造器:

  1. ArrayList(http://www.nvzi91.cn/chunvmoxiufu/29949.html)
  2. ArrayList(Collection<? extends E> c)
  3. ArrayList(int initialCapacity)
复制代码

Collection接口约定,每个集合类应该提供两个”标准”构造器,一个是无参数的构造器(上面第一个),另外一个是拥有单个参数(类型为Collettion)的构造器(上面第二个)。ArrayList还提供了第三个构造器,其接受一个int值,用于设置ArrayLi的初始大小(默认大小为10)。

相关方法 trimToSize
  1. public void trimToSize() {
  2. modCount++;
  3. int oldCapacity = elementData.length;
  4. if (size < oldCapacity) {
  5. elementData = Arrays.copyOf(elementData, size);
  6. }http://www.nvzi91.cn/niaodaoyan/29950.html
  7. }
复制代码

用于把ArrayList的容量缩减到当前实际大小,减少存储容量。其中的变量modCount由AbstracList继承而来,记录List发生结构化修改(structurally modified)的次数。elementData中实际存储了ArrayList的元素,在ArrayList中声明为:private transient Object[] elementData;变量size是ArrayList的元素数量,当size < oldCapacity时,调用Arrays.copyOf方法实现缩减。

indexOf 和 lasIndexOf
  1. public int indexOf(Object o) {
  2. if (o == null) {
  3. for (int i = 0; i < size; i++)
  4. if (elementData[i]==null)
  5. return i;http://www.nvzi91.cn/chunvmoxiufu/29951.html
  6. } else {
  7. for (int i = 0; i < size; i++)
  8. if (o.equals(elementData[i]))
  9. return i;
  10. }
  11. return -1;
  12. }http://www.nvzi91.cn/yindaoyan/29952.html
复制代码

这两个方法返回指定元素的下标,要区分参数是否为null。lastIndexOf和indexOf类似,只不过是从后往前搜索。

ensureCapacity
  1. public void ensureCapacity(int minCapacity) {
  2. if (minCapacity > 0)
  3. ensureCapacityInternal(minCapacity);
  4. }http://www.kmrlyy.com/fujianyan/33465.html
  5. private void ensureCapacityInternal(int minCapacity) {
  6. modCount++;
  7. // overflow-conscious code
  8. if (minCapacity - elementData.length > 0)
  9. grow(minCapacity);
  10. }http://www.kmrlyy.com/fujianyan/33466.html
  11. private void grow(int minCapacity) {
  12. // overflow-conscious code
  13. int oldCapacity = elementData.length;
  14. int newCapacity = oldCapacity + (oldCapacity >> 1);
  15. if (newCapacity - minCapacity < 0)
  16. newCapacity = minCapacity;
  17. if (newCapacity - MAX_ARRAY_SIZE > 0)
  18. newCapacity = hugeCapacity(minCapacity);
  19. // minCapacity is usually close to size, so this is a win:
  20. elementData = Arrays.copyOf(elementData, newCapacity);
  21. }http://www.kmrlyy.com/penqiangyan/33467.html
复制代码

这个方法可以确保ArrayList的大小

add 和 addAll
  1. public void add(int index, E element) {
  2. rangeCheckForAdd(index);
  3. ensureCapacityInternal(size + 1); // Increments modCount!!
  4. System.arraycopy(elementData, index, elementData, index + 1,
  5. size - index);
  6. elementData[index] = element;
  7. size++;
  8. }http://www.kmrlyy.com/gongjingai/33468.html
复制代码

add(int index, E element)向指定位置添加元素,首先调用rangeCheckForAdd检查index是否有效,如果index > size || index < 0将抛出异常。然后确保容量加1,调用System.arraycopy把从index开始的元素往后移动一个位置。最后把index处的值设置为添加的元素。还有一个重载的add(E e)方法是直接把元素添加到末尾。
addAll(Collection c)和addAll(int index, Collection c)则分别是向末尾和指定位置添加Collection中的所有元素。

remove 和 removeAll
  1. public boolean remove(Object o) {
  2. if (o == null) {
  3. for (int index = 0; index < size; index++)
  4. if (elementData[index] == null) {
  5. fastRemove(index);
  6. return true;
  7. }http://www.kmrlyy.com/gongjingai/33469.html
  8. } else {
  9. for (int index = 0; index < size; index++)
  10. if (o.equals(elementData[index])) {
  11. fastRemove(index);
  12. return true;
  13. }http://m.nvzi91.cn/gongjingfeida/29358.html
  14. }
  15. return false;
  16. }
复制代码

remove(Object o)方法删除指定的元素。首先是查找元素位置,然后调用fastRemove(index)删除,其代码如下:

  1. private void fastRemove(int index) {
  2. modCount++;
  3. int numMoved = size - index - 1;
  4. if (numMoved > 0)
  5. //把index+1往后的元素都往前移动一个位置
  6. System.arraycopy(elementData, index+1, elementData, index,
  7. numMoved);
  8. elementData[--size] = null; // Let gc do its work
  9. }http://m.nvzi91.cn/gongjingmilan/29359.html
复制代码

重载的remove(int index)方法用于删除指定位置的元素。removeRange(int fromIndex, int toIndex)用于删除指定位置之间的所有元素。
removeAll(Collection c)和retainAll(Collection c)代码如下:

  1. public boolean removeAll(Collection<?> c) {
  2. Objects.requireNonNull(c);
  3. return batchRemove(c, false);
  4. }
  5. public boolean retainAll(Collection<?> c) {
  6. Objects.requireNonNull(c);
  7. return batchRemove(c, true);
  8. }http://m.nvzi91.cn/gongjingjibing/29360.html
复制代码

它们都是通过调用batchRemove方法实现的,其代码如下:

  1. private boolean batchRemove(Collection<?> c, boolean complement) {
  2. final Object[] elementData = this.elementData;
  3. int r = 0, w = 0;
  4. boolean modified = false;
  5. try {www.nvzi91.c
  6. for (; r < size; r++)
  7. if (c.contains(elementData[r]) == complement)
  8. elementData[w++] = elementData[r];
  9. } finally {
  10. // Preserve behavioral compatibility with AbstractCollection,
  11. // even if c.contains() throws.
  12. if (r != size) {
  13. System.arraycopy(elementData, r,
  14. elementData, w,
  15. size - r);
  16. w += size - r;
  17. }www.kmrlyy.com
  18. if (w != size) {
  19. // clear to let GC do its work
  20. for (int i = w; i < size; i++)
  21. elementData[i] = null;
  22. modCount += size - w;
  23. size = w;
  24. modified = true;
  25. }
  26. }m.nvzi91.cn
  27. return modified;
  28. }
复制代码

这个方法有两个参数,第一个是操作的Collection,第二个是一个布尔值,通过设置为true或false来选择是removeAll还是retainAll。try里面的语句是把留下来的放在0到w之间,然后在finally中第二个if处理w之后的空间,第一个是在c.contains()抛出异常时执行。

展开阅读全文

没有更多推荐了,返回首页