资讯专栏INFORMATION COLUMN

Java ArrayList源码分析

DevTalking / 1049人阅读

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

ArrayList介绍

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

签名
public class ArrayList
extends AbstractList
implements List, RandomAccess, Cloneable, Serializable

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

构造器

ArrayList提供了三个构造器:

ArrayList()
ArrayList(Collection c)
ArrayList(int initialCapacity)

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

相关方法 trimToSize
public void trimToSize() {
        modCount++;
        int oldCapacity = elementData.length;
        if (size < oldCapacity) {
            elementData = Arrays.copyOf(elementData, size);
        }
    }

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

indexOflasIndexOf
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;
    }

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

ensureCapacity
public void ensureCapacity(int minCapacity) {
       if (minCapacity > 0)
           ensureCapacityInternal(minCapacity);
   }
private void ensureCapacityInternal(int minCapacity) {
        modCount++;
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
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);
    }

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

addaddAll
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++;
    }

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中的所有元素。

removeremoveAll
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;
    }

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

private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            //把index+1往后的元素都往前移动一个位置
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // Let gc do its work
    }

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

public boolean removeAll(Collection c) {
        Objects.requireNonNull(c);
        return batchRemove(c, false);
    }
public boolean retainAll(Collection c) {
        Objects.requireNonNull(c);
        return batchRemove(c, true);
    }

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

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;
    }

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64527.html

相关文章

  • Java集合源码分析系列-(一)ArrayList源码剖析

    摘要:需要注意的是,通过构造函数定义初始量是动态数组的实际大小。带容量的构造函数新建一个容量为的数组默认构造函数,默认为空构造一个包含指定元素的第一个构造方法使用提供的来初始化数组的大小。 前言 今天介绍经常使用的一个Java集合类——ArrayList(基于JDK1.8.0_121)。ArrayList在工作和日常面试中经常被使用或者提到。总的来说,工作中使用ArrayList主要是因为动...

    Miyang 评论0 收藏0
  • java源码

    摘要:集合源码解析回归基础,集合源码解析系列,持续更新和源码分析与是两个常用的操作字符串的类。这里我们从源码看下不同状态都是怎么处理的。 Java 集合深入理解:ArrayList 回归基础,Java 集合深入理解系列,持续更新~ JVM 源码分析之 System.currentTimeMillis 及 nanoTime 原理详解 JVM 源码分析之 System.currentTimeMi...

    Freeman 评论0 收藏0
  • Java集合干货——ArrayList源码分析

    摘要:关于的具体实现,一些基本的都也知道,譬如数组实现,线程不安全等等,但是更加具体的就很少去了解了,例如初始化的长度,扩容等。 前言 在之前的文章中我们提到过ArrayList,ArrayList可以说是每一个学java的人使用最多最熟练的集合了,但是知其然不知其所以然。关于ArrayList的具体实现,一些基本的都也知道,譬如数组实现,线程不安全等等,但是更加具体的就很少去了解了,例如:...

    Render 评论0 收藏0
  • Java集合干货——ArrayList源码分析

    摘要:关于的具体实现,一些基本的都也知道,譬如数组实现,线程不安全等等,但是更加具体的就很少去了解了,例如初始化的长度,扩容等。 前言 在之前的文章中我们提到过ArrayList,ArrayList可以说是每一个学java的人使用最多最熟练的集合了,但是知其然不知其所以然。关于ArrayList的具体实现,一些基本的都也知道,譬如数组实现,线程不安全等等,但是更加具体的就很少去了解了,例如:...

    wupengyu 评论0 收藏0
  • ConcurrentModificationException,iterator迭代问题[源码分析]

    摘要:单线程的迭代过程中删除集合元素以上代码会出现如下异常从后往前看第行代码我们在执行代码行时调用了这个是调用返回的对象这个对象的方法如下图方法首先它会调用这个方法这个方法很简单就是比较这两个值是不是相等不相等就抛出异常如下图这两个值为什么会不相 单线程的Iterator迭代过程中删除集合元素 public class TestIterator { public static voi...

    zhoutk 评论0 收藏0
  • ConcurrentModificationException,iterator迭代问题[源码分析]

    摘要:单线程的迭代过程中删除集合元素以上代码会出现如下异常从后往前看第行代码我们在执行代码行时调用了这个是调用返回的对象这个对象的方法如下图方法首先它会调用这个方法这个方法很简单就是比较这两个值是不是相等不相等就抛出异常如下图这两个值为什么会不相 单线程的Iterator迭代过程中删除集合元素 public class TestIterator { public static voi...

    aaron 评论0 收藏0

发表评论

0条评论

DevTalking

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<