Android常用集合List之实现类ArrayList解析

  • 前言
  • 主要属性
  • 构造方法解析
  • 几个主要的和常用的方法
  • modCount++

前言

基于Java1.8源码,层级结构就不再多叙述,只介绍几个内部方法解析

主要属性

    /**
     * Shared empty array instance used for empty instances.
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * 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 == EMPTY_ELEMENTDATA will be expanded to
     * DEFAULT_CAPACITY when the first element is added.
     *
     * Package private to allow access from java.util.Collections.
     */
    transient Object[] elementData;
    /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     */
    private int size;

解析:EMPTY_ELEMENTDATA 属性,从注释上看就是提供一个默认的空的数组;elementData 一个数组,里面存放的集合里面的所有数据 size 不做叙述了,大家都懂。

构造方法解析

//构造方法1 传入初始化 elementData容量,并创建一个容量为initialCapacity大小的数组
public ArrayList(int initialCapacity) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
    }
    /** 构造方法2 默认构造一个容量为10的数组
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        super();
        this.elementData = EMPTY_ELEMENTDATA;
    }
    //构造方法3 传入一个Collection的实现类(很多,List Set都是)就做了2步操作 数据的赋值和一步校验,校验代码可以去看Arrays这个类
    public ArrayList(Collection c) {
        elementData = c.toArray();
        size = elementData.length;
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    }

几个主要的和常用的方法

public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
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;
    }

解析: 通过indexOf方法找到对象下标位置(如果泛型不去重写equals方法,就按照默认的实现处理,具体应用中,equals方法经常会被重写,达到需要的判定对象是否是一个的标准),通过返回值判定是否有这个对象 注意实现,采用循环遍历,在实际应用中,一定要考虑数据量的问题

/**
     * Replaces the element at the specified position in this list with
     * the specified element.
     *
     * @param index index of the element to replace
     * @param element element to be stored at the specified position
     * @return the element previously at the specified position
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E set(int index, E element) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

        E oldValue = (E) elementData[index];
        elementData[index] = element;
        return oldValue;
    }

解析:通过下标去替换某个数据,并返回原来的对象。如源码所示,不难理解.


下面是(个人认为)是ArrayList的精髓所在  如何在存储方式是一个数组的情况下支持无限添加
/**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return true (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;

private void ensureCapacityInternal(int minCapacity) {
        if (elementData == EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }
private void ensureExplicitCapacity(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);
    }

解析:如 以上代码所示,添加一个数据 ensureCapacityInternal 字面解释就是确保内部存储的容量是正确的。看看他做了些事情: 1、先看传入值是 size+1 此刻还没有对size进行加操作,就可以认为这是一个预容器容量 2、如果是默认构造产生的存储对象 就比较两值取最大值 3、如果不是默认构造对象 这个时候就要明确内部存储的容量大小了 就是 ensureExplicitCapacity 这个方法 首先modCount++ 这个是干嘛的?稍后简单说下。 然后校验数组长度是否足够,如果不够,进行扩容操作。这个扩容操作简单说下吧,第一步,进行原长度1.5倍扩容;第二部,校验这个1.5倍的扩容值是否能够满足预需要长度,如不足进行替换;第三步,校验数组最大容量为,代码很明显一看就知道;最后拷贝新数组。
最后一步进行size++替换

remove方法

 public E remove(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

        modCount++;
        E oldValue = (E) 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;
    }

解析:通过下标删除某个数据。实现原理,通过系统方法复制。该方法含义,将目标数组a从index+1位置开始的数据复制到数组b的index以后。第一个数组为数组a,第二个数组为数组b 最后一个参数是需要拷贝的个数,通过这个方法就实现了数据从数组中移除出去,最后size要执行–操作

添加一个Collection

public boolean addAll(Collection 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;
    }

解析:同样需要确保数组容量的正确性,代码上文已解释,然后处理这部分添加的数据。方法如同remove的复制方法,不再解释

public boolean addAll(int index, Collection c) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(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;
    }

解析 如代码所示,添加到指定位置。有两部主要操作,第一部分,将原本index以后的数据插入到index+numNew之后,第二部,将Collection的所有数据插入到数组的index之后

modCount++

这个操作伴随着整个ArrayList的增删操作都会加一。具体在那里用到了?List接口有个方法是iterator(),就是迭代器这一步操作.
首先看看ArrayList的最简单实现(为啥是最简单的,因为有的部分操作目前还没有时间整理,整个源码部分还有一点其他的模块没有说到)

public Iterator iterator() {
        return new Itr();
    }

再看看Itr的源码

/**
     * An optimized version of AbstractList.Itr
     */
    private class Itr implements Iterator<E> {
        // The "limit" of this iterator. This is the size of the list at the time the
        // iterator was created. Adding & removing elements will invalidate the iteration
        // anyway (and cause next() to throw) so saving this value will guarantee that the
        // value of hasNext() remains stable and won't flap between true and false when elements
        // are added and removed from the list.
        protected int limit = ArrayList.this.size;

        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        public boolean hasNext() {
            return cursor < limit;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            int i = cursor;
            if (i >= limit)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
                limit--;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumersuper E> consumer) {
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;

            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

解析:这是ArrayList的一个内部类,在初始化的时候modCount就赋值给expectedModCount,这一步操纵是为了防止在初始化一个新的迭代器之后依旧有增删操作,那么就会直接影响迭代器的 方法,通过这个modCount去判定在使用迭代器的时候是否是最新的准确的数据,每次有数据操作之后再次使用迭代器,应当重新初始化。

你可能感兴趣的:(Android,Java)