jdk8源码2---集合1---ArrayList

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wxy540843763/article/details/80640604

一、 签名

public class ArrayList<E> extends AbstractList<E>

        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

可序列化,可以支持快速的随机访问,可以被克隆。

二、成员变量

private static final int DEFAULT_CAPACITY = 10; // 默认大小为10

private static final Object[] EMPTY_ELEMENTDATA = {};

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

transient Object[] elementData;  // arrayList中的数据

private int size;  // 当前状态下的arraylist中的数据量。

Protect transient int modCount = 0; // 记录被修改的次数。

 

三、构造方法

public ArrayList(int initialCapacity) {  // 可以指定容量的大小。

        if (initialCapacity > 0) {  //如果指定了容量大小,那么就会创建指定容量的list

            this.elementData = new Object[initialCapacity];

        } else if (initialCapacity == 0) {

            this.elementData = EMPTY_ELEMENTDATA;

        } else {

            throw new IllegalArgumentException("Illegal Capacity: "+

                                               initialCapacity);

        }

    }

public ArrayList() {

this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; //使用默认的数据大小

}//但是,DEFAULTCAPACITY_EMPTY_ELEMENTDATA的大小也是0,为什么呢?是在第一次调用add的时候将其初始化的。见add方法。

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;

        }

    }

 

四、成员方法

1.1     add

public boolean add(E e) {

    ensureCapacityInternal(size + 1);  // Increments modCount!!

    elementData[size++] = e;

    return true;

}

private void ensureCapacityInternal(int minCapacity) { //minCapacity当前的容量

       if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//此时即第一次add

       minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);//设置容量为10

    }

ensureExplicitCapacity(minCapacity); // 需要的最小容量。

}

private void ensureExplicitCapacity(int minCapacity) {

        modCount++;

        // overflow-conscious code

        if (minCapacity - elementData.length > 0) //需要扩容了。

            grow(minCapacity); //扩容的大小为目前的size+1

    }

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

    }

private static int hugeCapacity(int minCapacity) {

        if (minCapacity < 0) // overflow

            throw new OutOfMemoryError();

        return (minCapacity > MAX_ARRAY_SIZE) ?

            Integer.MAX_VALUE :

            MAX_ARRAY_SIZE;// Integer.MAX_VALUE-8

    }

扩容的算法是:

1.  指定下次预期扩容的为当前容量的二分之三倍,称之为新容量(newCapacity),如果需要的最小容量(minCapacity)大于新容量(newCapacity),那么就以需要的最小容量(minCapacity)扩容。如果新容量(newCapacity)大于了规定的最大数组大小(Integr.MAX_VALUE-8),那么就将需要的最小容量(minCapacity)和最大数组大小(Integr.MAX_VALUE-8)比较,取大。如果最小容量(minCapacity)大于规定的最大数组大小(Integr.MAX_VALUE-8),扩容后的数组大小为Integr.MAX_VALUE

1.2 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++;

    }

public static native void arraycopy(Object src,  int  srcPos,

               Object dest, int destPos, int length);

 

添加一个集合中的所有元素的时候,调用的是System.arraycopy方法。注意,调用的这个方法是一个本地方法。

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

    }

    *System.arraycopy

    像其他的和添加相关的方法都是差不多了。不一一列举。

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

    }

    很简单,不多说。

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

    }

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

    }

    同样的 内涵之处还是在System.arraycopy

2.3 public booleanremoveAll(Collection<?> c)

public boolean removeAll(Collection<?> c) {

        Objects.requireNonNull(c);

        return batchRemove(c, false);

    }

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;

    }

3.1 public E get(int index)

public E get(int index) {

    rangeCheck(index); 

return elementData(index);

}

E elementData(int index) {

        return (E) elementData[index];   // 毕竟是数组。

    }

 

4. 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;

    }

 

5. public boolean contains(Object o)

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;

    }

 

 

五、遍历方式

1.  for循环。

2.  fori

3.  IteratorArrayList.iterator();

public Iterator<E> iterator() { return new Itr(); }

private class Itr implements Iterator<E> {

        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 != size;

        }

        @SuppressWarnings("unchecked")

        public E next() {

            checkForComodification();

            int i = cursor;   // cursor 当前元素的指针。

            if (i >= size)

                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();

            checkForComodification();

            try {

                ArrayList.this.remove(lastRet);

                cursor = lastRet;

                lastRet = -1;

                expectedModCount = modCount;

            } catch (IndexOutOfBoundsException ex) {

                throw new ConcurrentModificationException();

            }

        }

 

        @Override

        @SuppressWarnings("unchecked")

        public void forEachRemaining(Consumer<? super 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;

            checkForComodification();

        }

 

        final void checkForComodification() {

            if (modCount != expectedModCount)

                throw new ConcurrentModificationException();

        }

    }

 

定义了一个内部类,实现了Iterator接口。实现其方法。

用一个变量来记录当前访问的元素的地址,这个变量必须是成员变量。

不定义内部类,直接用ArrayList实现Iterator接口,也是可以的。

 

 

总结:

    先说一些老生常谈的事情吧。

    1.ArrayList的实现原理是数组。

    2.容量不固定,最大值是Integer.MAX

    3.元素允许为null

4.有序(重申:放入和取出是有序的)

    5.非线程安全。

       并发环境下,要么加锁,要么在初始化时使用Collection.synchronizeList(newArrayList());

6.遍历时的效率问题:

for循环要比迭代器快。原因是ArrayList继承了RandomAccess,支持快速的随机访问,而迭代器都是基于ArrayList方法和数组直接操作的。

 

7.addremove值类型的数据时可能会涉及拆装箱操作。

 

补充一下:

    Fail-fast机制,也叫作快速失败机制,是java集合中的一种错误检测机制。

    ArrayList中,有个modCount的变量,每次进行addsetremove等操作,都会执行modCount++.

在获取ArrayList迭代器时,会将ArrayList中的modCount保存在迭代中,每次执行addsetremove等操作,都会执行一次检查,都会调用checkForComodification方法,对modCount进行比较,如果迭代器中的modCountlist中的modCount不同,就会抛出ConcurrentModificationException

猜你喜欢

转载自blog.csdn.net/wxy540843763/article/details/80640604