JAVA-容器(3)-List

(基于JDK1.8源码分析)

一,List接口

  1,继承Collection接口,实现了集合的有序存储; 对元素位置进行精确控制,根据索引对集合进行访问和遍历;

  2,源码分析

public interface List<E> extends Collection<E> {

    int size();
    boolean isEmpty();
    boolean contains(Object o);
    Iterator<E> iterator();
    Object[] toArray();
    <T> T[] toArray(T[] a);
    boolean add(E e);
    boolean remove(Object o);
    boolean containsAll(Collection<?> c);
    boolean addAll(Collection<? extends E> c);
    boolean addAll(int index, Collection<? extends E> c);
    boolean removeAll(Collection<?> c);
    boolean retainAll(Collection<?> c);

    /***/
    default void replaceAll(UnaryOperator<E> operator) {
        Objects.requireNonNull(operator);
        final ListIterator<E> li = this.listIterator();
        while (li.hasNext()) {
            li.set(operator.apply(li.next()));
        }
    }

    /***/
    @SuppressWarnings({"unchecked", "rawtypes"})
    default void sort(Comparator<? super E> c) {
        Object[] a = this.toArray();
        Arrays.sort(a, (Comparator) c);
        ListIterator<E> i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
        }
    }

    void clear();
    boolean equals(Object o);
    int hashCode();
/** 返回指定索引位置元素*/ E get(int index); /** 设置指定索引位置元素*/ E set(int index, E element); /** 在指定索引位置新增元素*/ void add(int index, E element); /** 删除指定索引位置元素*/ E remove(int index); /** 返回指定对象最小索引位置*/ int indexOf(Object o); /** 返回指定对象最大索引位置,主要用于重复元素*/ int lastIndexOf(Object o); /** 返回迭代器默认索引位置为0; 支持前后遍历,原理是改变集合当前的索引位置*/ ListIterator<E> listIterator(); /** 返回迭代器并指定默认索引位置为index*/ ListIterator<E> listIterator(int index);
/** 返回指定索引间的元素集合*/ List<E> subList(int fromIndex, int toIndex);
/***/ @Override default Spliterator<E> spliterator() { return Spliterators.spliterator(this, Spliterator.ORDERED); }

二,ArrayList实现

  public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

  RandomAccess: List实现使用的标记接口,用于提高连续或随机访问性能

  Cloneable: 实现Cloneable可以对该类实例进行克隆

  Serializable:用于表示可序列化

  【1】底层实现

         ArrayList底层通过数组实现

    transient Object[] elementData;  //transient避免Serializable持久化

  【2】构造方法

  /** 指定空间大小*/
    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;
    }
    /** 将指定集合转为数组  1-集合转数组  2-数组大小为0使用空数组替换  3-数组大小>0进行数组拷贝*/
    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;
        }
    }

  【3】新增

  /** 设置指定索引位置元素    1-检查指定索引是否向前越界 2-获取指定索引位置原元素 3-将指定元素赋值到指定索引位置*/
    public E set(int index, E element) {
        rangeCheck(index);    //(index >= size)向前越界

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

    /** 新增元素    1-容器扩容 2-将指定元素赋值到最大索引位置 */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

    /** 新增元素到指定索引位置     1-检查索引是否越界 2-容器扩容 3-将指定索引位置右端元素右移 4-设置指定元素到指定索引位置*/
    public void add(int index, E element) {
        rangeCheckForAdd(index);    //(index > size || index < 0)越界

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }
  
/** 新增集合中所有元素 1-将指定集合转数组 2-容器扩容 3-将转后数组添加到扩容前最大索引位置 4-容器扩容,大小为指定集合大小*/ 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; } /** 新增集合中所有元素到指定索引位置 1-检查指定索引越界 2-指定集合转数组 3-容器扩容 4-将扩容前最大索引位置右端元素右移 5-将换后数组添加到扩容前最大索引位置 6-容器扩容*/ public boolean addAll(int index, Collection<? extends E> c) { rangeCheckForAdd(index); //(index > size || index < 0) 越界 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; }

   【4】查询

  /** 获取指定索引位置元素  1-检查索引向前越界 2-获取指定索引位置元素*/
    public E get(int index) {
        rangeCheck(index);   //(index >= size) 向前越界

        return elementData(index);
    }

    【5】删除  (①指定索引位置 ②指定元素)

  /** 删除指定索引位置元素  1-检查索引向前越界 2-获取删除后需要左移元素总数 3-将指定索引+1位元素左移 4-将最大索引位置空*/
    public E remove(int index) {
        rangeCheck(index);  //(index >= size) 向前越界

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

    /** 删除指定元素在容器中首次出现的元素 */
    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(int index)但是无索引越界检查 */
    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
    }

    /** 容器清空 */
    public void clear() {
        modCount++;

        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }

   【6】容器扩容

  /** 容器扩容-1 */
    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);
        }
    }
  /** 容器扩容-2*/
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_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);
    }

  /** 新增元素集合之后的size > 集合容量,进行50%扩容 */
    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);
    }

    【7】将底层数组大小调整为实际集合中元素数量

    

 /**
     * Trims the capacity of this <tt>ArrayList</tt> instance to be the
     * list's current size.  An application can use this operation to minimize
     * the storage of an <tt>ArrayList</tt> instance.
     */
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

    【8】Fail-fast(快速失败机制)

     modCount++  :记录修改此列表的次数(包括:修改列表元素,大小,顺序)

     定义:ArrayList是线程不安全的,如果使用迭代器过程中其他线程修改了List,会出现异常(ConcurrentModificationException)

    原理:ArrayList使用迭代器时,只允许迭代器对List进行remove,add,如果其他线程对List的修改迭代器会立刻出现异常,快速失败

    【9】迭代器

    checkForComodification(): 用于检查快速失败机制
    多线程同时操作同一个ArrayList时发现modCount不一致,出现快速失败ConcurrentModificationException异常
  /** 返回迭代器 */
    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; 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(); } }

   【10】子列表 

    subList(int fromIndex, int toIndex)对子列表的修改会同时修改原列表
      List<String> a = new ArrayList<String>();
        a.add("a");
        a.add("b");
        a.add("c");
        a.add("d");
        List<String> a1 = a.subList(1, 2);
        a1.add("e");               //此操作会同时修改a和a1列表    a列表: a,b,e,c,d   a1列表:b,e
        a1.remove("b");            //此操作会同时修改a和a1列表    a列表: a,e,c,d     a1列表:e

    源码:

  /** 获取指定索引段之间的元素并以列表形式返回*/
    public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);
        return new SubList(this, 0, fromIndex, toIndex);
    }



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

        public List<E> subList(int fromIndex, int toIndex) {
            subListRangeCheck(fromIndex, toIndex, size);
            return new SubList(this, offset, fromIndex, toIndex);
        }

        private void rangeCheck(int index) {
            if (index < 0 || index >= this.size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }

        private void rangeCheckForAdd(int index) {
            if (index < 0 || index > this.size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }

        private String outOfBoundsMsg(int index) {
            return "Index: "+index+", Size: "+this.size;
        }

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

        public Spliterator<E> spliterator() {
            checkForComodification();
            return new ArrayListSpliterator<E>(ArrayList.this, offset,
                                               offset + this.size, this.modCount);
        }
    }

   【11】ArrayList和Vector区别

      ArrayList:异步

      Vector:同步

     同步:

        定义:多线程对于共享资源同一时间点只允许一个线程占用资源,其他线程等待 (线程安全)

        适用:多个线程共享同一个数据,就适用同步,否则会出现例如数据库脏读,不可重复读,幻读等现象

     异步:

        定义:只有一个线程访问当前数据     (线程不安全)

     

package com.test;

import java.util.ArrayList;
import java.util.Iterator;

public class Test implements Runnable {
    private ArrayList<String> aa = new ArrayList<String>();

    @Override
    public void run() {
        aa.set(0, "Thread");
    }

    public String get() {
        aa.add("ThreadMain");
        System.out.println(aa.get(0).toString());
        Iterator it = aa.iterator();
        return aa.get(0).toString();
    }

    public static void main(String[] args) throws InterruptedException {

        Test test = new Test();
        new Thread(test).start();
        System.out.println(test.get());

        /**
         * 执行结果: ThreadMain Thread
         */

    }

}

      

原文地址:https://www.cnblogs.com/wanhua-wu/p/6653796.html