Java 笔记 20:List,Arraylist 源码

Java 笔记 20


Collection是根接口,没有提供任何直接实现的。它有一些更具体的子接口,例如:List和Set。

  • 一、List:列表,接口
  • 1、List系列的集合:有序的、可重复的
  • 2、List系列的集合:ArrayList(动态数组)、Vector(动态数组,向量类)、
  •  	LinkedList(双向链表、双端队列、栈..)、Stack(栈)
    
  • 3、List的API
  • List接口比Collection接口多了一堆方法:
  • 下面列举的方法是比Collection接口多出来,和它一样的就不写了:
  • (1)void add(int index, Object element) :在[index]位置添加一个元素,相当于插入
  • boolean addAll(int index, Collection c) :在[index]位置添加多个元素
    
  • (2) Object remove(int index) :删除指定位置的元素
  • (3)Object get(int index) :获取,返回[index]位置的元素
  • (4)Object set(int index, Object element) :替换[index]位置的元素为element
  • (5)int indexOf(Object o) :在当前集合中查找o这个元素的下标,如果没有返回-1,如果有多个就返回找到的第一个的下标
  • (6) int lastIndexOf(Object o) :在当前集合中查找o这个元素的下标,如果没有返回-1,如果有多个就返回找到的最后一个的下标
  • (7)List subList(int fromIndex, int toIndex) :截取一部分,[fromIndex, toIndex)
  • (8)ListIterator listIterator() :获取一种迭代器
  • ListIterator是Iterator的子接口,它比Iterator增加了:从后往前遍历的方法,增加了遍历的同时添加和修改。
  • Iterator:
  • (1)boolean hasNext()
  • (2)Object next()
  • (3)void remove()
  • ListIterator:多出来的
  • (1)boolean hasPrevious() :是否前面还有元素
  • (2)Object previous() :获取前面的元素
  • (3)void add(E e) :遍历的同时,添加元素
  • (4)void set(E e) :遍历的同时,替换元素
  • (5) int nextIndex() :返回下一个元素的索引
  • (6)int previousIndex() :返回前一个元素的索引
  • 说明:虽然List系列的集合都是可以通过索引/下标进行操作的,但是像LinkedList这类的集合,其实不建议使用和索引相关的方法进行操作。
  • 因为它们的底层的物理结构不是数组,如果通过索引操作呢,会需要从头或尾遍历找到对应的索引,效率不高。

ArrayList源码分析

private static final long serialVersionUID
用于类的序列化,
https://blog.csdn.net/u014750606/article/details/80040130

private static final int DEFAULT_CAPACITY = 10;
数组初始化时默认构造的容量。与size()方法不同,size()返回的是逻辑长度。
https://blog.csdn.net/shmily_lsl/article/details/84141353

private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
https://blog.csdn.net/weixin_43390562/article/details/101236833

当无参构造时,Obeject数组elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

当有参构造时,如果给定初始容量为0,或者传入集合为空集合(不是null),那么,将空数组EMPTY_ELEMENTDATA赋给elementData;

transient Object[] elementData;
transient用来表示一个域不是该对象序行化的一部分
https://blog.csdn.net/zero__007/article/details/52166306

private int size
数组逻辑长度。

根据初始化容量进行的有参构造
    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);
        }
    }
无参构造,构造一个初始容量为 10 的空列表。
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

关于Collection<? extends E> c

https://blog.csdn.net/wuxinliulei/article/details/38474367?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param


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

关于trimToSize()
https://www.cnblogs.com/hfczgo/p/4062826.html

删除多余增长容量
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

关于public void ensureCapacity(int minCapacity)
ArrayList 源码中有一个 ensureCapacity 方法,这个方法显然是用做扩容用的,这个方法 ArrayList 内部没有被调用过,所以很显然是提供给用户调用的,这个方法最好在 add 大量元素之前调用,以减少增量重新分配的次数

如果是DEFAULTCAPACITY_EMPTY_ELEMENTDATA,它有默认的10容量,需要先行考虑。
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // any size if not default element table
            ? 0
            // larger than default for default empty table. It's already
            // supposed to be at default size.
            : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }

如果容量不够,使用grow方法进行扩容
    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);
    }


如果新数组的最小容量比MAX_ARRAY_SIZE大,
那么说明这个要返回的真正扩充的空间也要大于MAX_ARRAY_SIZE,
所以取 Integer.MAX_VALUE。
如果比MAX_ARRAY_SIZE小,那么取MAX_ARRAY_SIZE即可。
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
数组也是对象,需要8个字节来记录对象头信息



    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

根据是不是DEFAULTCAPACITY_EMPTY_ELEMENTDATA,
来返回 minCapacity或者DEFAULT_CAPACITY
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }
    public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            //保证该clone是深复制,不加这句话,则复制的ArrayList对象中elementData指向的还是原对象中的数组。
            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);
        }
    }
    
Arrays.copyOf这个方法拷贝了原数组,返回一个新的数组,
这个拷贝的过程中到底是值传递还是指针传递,
尝试了一下,结果是指针传递,
也就是说,虽然Arrays.copyOf虽然返回了一个新的数组,
和原来的数组没有什么关系,
但是这两个数组里面的内容都是指向同一个引用的
    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }


https://www.jianshu.com/p/41795a983c90
这里没看懂,学完了泛型再看

    public <T> T[] toArray(T[] a) {
        if (a.length < size)
            // Make a new array of a's runtime type, but my contents:
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
        System.arraycopy(elementData, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }
    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++)
            //complement    为false的时候,删除交集,为true的时候,取交集,删除其他
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r];
        } finally {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            //如果contains方法使用过程报异常,将剩余的元素赋给该集合,如果不出现异常的话,是不会进入这个代码块的
            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;
    }

这里等学完了IO再看

    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{
        // Write out element count, and any hidden stuff
        int expectedModCount = modCount;
        s.defaultWriteObject();

        // Write out size as capacity for behavioural compatibility with clone()
        s.writeInt(size);

        // Write out all elements in the proper order.
        for (int i=0; i<size; i++) {
            s.writeObject(elementData[i]);
        }

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


    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        elementData = EMPTY_ELEMENTDATA;

        // Read in size, and any hidden stuff
        s.defaultReadObject();

        // Read in capacity
        s.readInt(); // ignored

        if (size > 0) {
            // be like clone(), allocate array based upon size not capacity
            int capacity = calculateCapacity(elementData, size);
            SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
            ensureCapacityInternal(size);

            Object[] a = elementData;
            // Read in all elements in the proper order.
            for (int i=0; i<size; i++) {
                a[i] = s.readObject();
            }
        }
    }

Comsumer 相关(没看懂)
https://blog.csdn.net/chuji2012/article/details/77871011

    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;

        Itr() {}

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            //逻辑长度
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            //边迭代边修改,会报错ConcurrentModificationException
            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();
        }
    }
private class ListItr extends Itr implements ListIterator<E> {
        ListItr(int index) {
            super();
            cursor = index;
        }

        public boolean hasPrevious() {
            return cursor != 0;
        }

        public int nextIndex() {
            return cursor;
        }

        public int previousIndex() {
            return cursor - 1;
        }

        @SuppressWarnings("unchecked")
        public E previous() {
            checkForComodification();
            int i = cursor - 1;
            if (i < 0)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i;
            return (E) elementData[lastRet = i];
        }

        public void set(E e) {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.set(lastRet, e);
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        public void add(E e) {
            checkForComodification();

            try {
                int i = cursor;
                ArrayList.this.add(i, e);
                cursor = i + 1;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    }
private class SubList extends AbstractList<E> implements RandomAccess {
        private final AbstractList<E> parent;//引用调用的父集合
        private final int parentOffset;//父集合的起始位置
        private final int offset;//原对象的起始位置
        int size;

        SubList(AbstractList<E> parent,
                int offset, int fromIndex, int toIndex) {
            this.parent = parent;
            this.parentOffset = fromIndex;
            this.offset = offset + fromIndex;
            this.size = toIndex - fromIndex;
            this.modCount = ArrayList.this.modCount;
        }

        public E set(int index, E e) {
            rangeCheck(index);
            checkForComodification();
            E oldValue = ArrayList.this.elementData(offset + index);
            ArrayList.this.elementData[offset + index] = e;
            return oldValue;
        }

        public E get(int index) {
            rangeCheck(index);
            checkForComodification();
            return ArrayList.this.elementData(offset + index);
        }

        public int size() {
            checkForComodification();
            return this.size;
        }

        public void add(int index, E e) {
            rangeCheckForAdd(index);
            checkForComodification();
            parent.add(parentOffset + index, e);
            this.modCount = parent.modCount;
            this.size++;
        }

        public E remove(int index) {
            rangeCheck(index);
            checkForComodification();
            E result = parent.remove(parentOffset + index);
            this.modCount = parent.modCount;
            this.size--;
            return result;
        }

        protected void removeRange(int fromIndex, int toIndex) {
            checkForComodification();
            parent.removeRange(parentOffset + fromIndex,
                               parentOffset + toIndex);
            this.modCount = parent.modCount;
            this.size -= toIndex - fromIndex;
        }

        public boolean addAll(Collection<? extends E> c) {
            return addAll(this.size, c);
        }

        public boolean addAll(int index, Collection<? extends E> c) {
            rangeCheckForAdd(index);
            int cSize = c.size();
            if (cSize==0)
                return false;

            checkForComodification();
            parent.addAll(parentOffset + index, c);
            this.modCount = parent.modCount;
            this.size += cSize;
            return true;
        }

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

        public ListIterator<E> listIterator(final int index) {
            checkForComodification();
            rangeCheckForAdd(index);
            final int offset = this.offset;

            return new ListIterator<E>() {
                int cursor = index;
                int lastRet = -1;
                int expectedModCount = ArrayList.this.modCount;

                public boolean hasNext() {
                    return cursor != SubList.this.size;
                }

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

                public boolean hasPrevious() {
                    return cursor != 0;
                }

                @SuppressWarnings("unchecked")
                public E previous() {
                    checkForComodification();
                    int i = cursor - 1;
                    if (i < 0)
                        throw new NoSuchElementException();
                    Object[] elementData = ArrayList.this.elementData;
                    if (offset + i >= elementData.length)
                        throw new ConcurrentModificationException();
                    cursor = i;
                    return (E) elementData[offset + (lastRet = i)];
                }

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

                public int nextIndex() {
                    return cursor;
                }

                public int previousIndex() {
                    return cursor - 1;
                }

                public void remove() {
                    if (lastRet < 0)
                        throw new IllegalStateException();
                    checkForComodification();

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

                public void set(E e) {
                    if (lastRet < 0)
                        throw new IllegalStateException();
                    checkForComodification();

                    try {
                        ArrayList.this.set(offset + lastRet, e);
                    } catch (IndexOutOfBoundsException ex) {
                        throw new ConcurrentModificationException();
                    }
                }

                public void add(E e) {
                    checkForComodification();

                    try {
                        int i = cursor;
                        SubList.this.add(i, e);
                        cursor = i + 1;
                        lastRet = -1;
                        expectedModCount = ArrayList.this.modCount;
                    } catch (IndexOutOfBoundsException ex) {
                        throw new ConcurrentModificationException();
                    }
                }

                final void checkForComodification() {
                    if (expectedModCount != ArrayList.this.modCount)
                        throw new ConcurrentModificationException();
                }
            };
        }

猜你喜欢

转载自blog.csdn.net/qq_40473204/article/details/107594145