zoukankan      html  css  js  c++  java
  • Java集合包(三)——List实现类之ArrayList与Vector原理分析

    转载请注明原文地址: https://www.cnblogs.com/ygj0930/p/13560541.html

    一:ArrayList特征

      ArrayList 是一个 动态数组。与Java中的基本数组相比,它的容量能动态增长。

      ArrayList中的操作不是线程安全的,建议在单线程环境下使用。多线程中可以选择JUC并发包中的CopyOnWriteArrayList。

    二:ArrayList的继承与实现关系

      

    1、继承层次

    java.lang.Object
       ↳     java.util.AbstractCollection<E>
             ↳     java.util.AbstractList<E>
                   ↳     java.util.ArrayList<E>

    2、类定义与实现

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

     1)ArrayList 继承了AbstractList抽象类,并实现了List接口。因此它可以提供相关的添加、删除、修改、遍历等功能。

     2)ArrayList 实现了RandmoAccess接口,提供了快速随机访问的功能。

     3)ArrayList 实现了Cloneable接口,覆盖了clone()方法,因此可以被克隆。

     4)ArrayList 实现java.io.Serializable接口,支持序列化。

    三:ArrayList原理

      ArrayList中包含两个重要的成员:elementData数组 和 size变量。

      1)elementData 数组是"Object[]类型的数组",它保存了添加到ArrayList中的元素:此处涉及泛型擦除的知识,请移步相关博文或自行百度

      elementData是个动态数组,我们能通过构造函数 ArrayList(int initialCapacity)来执行它的初始容量为initialCapacity;如果通过不含参数的构造函数ArrayList()来创建ArrayList,则elementData的容量默认是10。

      elementData数组的大小会根据ArrayList容量的增长而动态的增长:当ArrayList容量不足以容纳全部元素时,ArrayList会重新设置容量:新的容量=“(原始容量x3)/2 + 1”

      2) size 则是动态数组的实际大小。

      3)ArrayList重写了clone()方法,将全部元素克隆到一个新数组中并设置为elementData成员的引用。

      4) ArrayList的序列化与反序列化的方式:序列化时,先写入“容量”,再依次写入“每一个元素”;反序列化时,先读取“容量”,再依次读取“每一个元素”。

    四:ArrayList的关键方法

      1、数组容量检查并扩容

     50     // 确定ArrarList的容量。
     51     // 若ArrayList的容量不足以容纳当前的全部元素,设置 新的容量=“(原始容量x3)/2 + 1”
     52     public void ensureCapacity(int minCapacity) {
     53         // 将“修改统计数”+1
     54         modCount++;
     55         int oldCapacity = elementData.length;
     56         // 若当前容量不足以容纳当前的元素个数,设置 新的容量=“(原始容量x3)/2 + 1”
     57         if (minCapacity > oldCapacity) {
     58             Object oldData[] = elementData;
     59             int newCapacity = (oldCapacity * 3)/2 + 1;
     60             if (newCapacity < minCapacity)
     61                 newCapacity = minCapacity;
     62             elementData = Arrays.copyOf(elementData, newCapacity);
     63         }
     64     }

      该方法在add方法中被调用:

    // 添加元素e
     67     public boolean add(E e) {
     68         // 确定ArrayList的容量大小
     69         ensureCapacity(size + 1);  // Increments modCount!!
     70         // 添加e到ArrayList中
     71         elementData[size++] = e;
     72         return true;
     73     }

      确保添加元素前,数组的容量足够。

      2、迭代与内容访问

      (1) 快速随机访问,通过索引值访问内容。
      由于ArrayList实现了RandomAccess接口,它支持通过索引值去随机访问元素。

    list.get(i)

      (2) 通过迭代器遍历

    Iterator iter = list.iterator();
    while (iter.hasNext()) {
        value = (Integer)iter.next();
    }

      (03) for循环遍历

    for (Integer integ:list) {
        value = integ;
    }

      效率对比:快速随机访问>for循环遍历>迭代器遍历。

      原因:快速随机访问可以直接找到元素,for循环遍历复用了快速随机访问机制因此比较快,迭代器需要从头开始迭代并且有hashNext()等相关操作因此比较慢。

      3、数组转换

      有时我们需要将ArrayList转换回Java基本数组,此时需要调用toArray方法。

      ArrayList中对toArray方法进行了重载,分别有以下两种实现:

      1)Object[] toArray()

    // 返回ArrayList的Object数组
    134     public Object[] toArray() {
    135         return Arrays.copyOf(elementData, size);
    136     }

      该方法直接将ArrayList中的elementData数组内容拷贝一份并返回,由于类型擦除的原因,该数组存储的是Object对象,因此返回的是Object数组。

      需要注意:此时在调用处只能用Object[] x 变量来接收返回值,如果用其他类型数组强制接收会出行类型转换异常,因为不能直接将Object类型转换为基本类型。

      2)<T> T[] toArray(T[] a)

      // 返回ArrayList的模板数组。所谓模板数组,即可以将T设为任意的数据类型
    139     public <T> T[] toArray(T[] a) {
    140         // 若数组a的大小 < ArrayList的元素个数;
    141         // 则新建一个T[]数组,数组大小是“ArrayList的元素个数”,并将“ArrayList”全部拷贝到新数组中
    142         if (a.length < size)
    143             return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    144 
    145         // 若数组a的大小 >= ArrayList的元素个数;
    146         // 则将ArrayList的全部元素都拷贝到数组a中。
    147         System.arraycopy(elementData, 0, a, 0, size);
    148         if (a.length > size)
    149             a[size] = null;
    150         return a;
    151     }

      该方法需要传入一个模板数组作为参数,用来承载ArrayList数组中的内容,并返回接受拷贝后该参数的引用。

      在此方法中,ArrayList中的数组内容拷贝到容器数组时,会按照传进来的模板参数数组的实际类型来进行转换,然后再复制进模板数组中。

      调用示例:

     Integer[] newArray = (Integer[])arrayList.toArray(new Integer[n]);//参数为一个某确定长度的确定类型的基本数组

    五:Vector【已过时】

      1、特征

      Vector是一个动态数组,但是它是线程安全的。

      Vector元素的访问,使用索引的随机访问方式最快,使用迭代器最慢。

      Vector通过为方法加synchronized 来实现线程安全。

      2、原理

      Vector的数据结构和ArrayList差不多,它包含了3个成员变量:elementData数组 , elementCount, capacityIncrement。

      (01) elementData 是"Object[]类型的数组",它保存了添加到Vector中的元素。

      elementData是个动态数组,如果初始化Vector时,没指定动态数组的>大小,则使用默认大小10。

      随着Vector中元素的增加,Vector的容量也会动态增长,若容量增加系数 >0,则将容量的值增加“容量增加系数”;否则,将容量大小增加一倍。

      (02) elementCount 是动态数组的实际大小。

      (03) capacityIncrement 是动态数组的增长系数。如果在创建Vector时,指定了capacityIncrement的大小;则,每次当Vector中动态数组容量增加时>,增加的大小都是capacityIncrement。

      3、源码分析

    package java.util;
    
    public class Vector<E>
        extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    {
    
        // 保存Vector中数据的数组
        protected Object[] elementData;
    
        // 实际数据的数量
        protected int elementCount;
    
        // 容量增长系数
        protected int capacityIncrement;
    
        // Vector的序列版本号
        private static final long serialVersionUID = -2767605614048989439L;
    
        // Vector构造函数。默认容量是10。
        public Vector() {
            this(10);
        }
    
        // 指定Vector容量大小的构造函数
        public Vector(int initialCapacity) {
            this(initialCapacity, 0);
        }
    
        // 指定Vector"容量大小"和"增长系数"的构造函数
        public Vector(int initialCapacity, int capacityIncrement) {
            super();
            if (initialCapacity < 0)
                throw new IllegalArgumentException("Illegal Capacity: "+
                                                   initialCapacity);
            // 新建一个数组,数组容量是initialCapacity
            this.elementData = new Object[initialCapacity];
            // 设置容量增长系数
            this.capacityIncrement = capacityIncrement;
        }
    
        // 指定集合的Vector构造函数。
        public Vector(Collection<? extends E> c) {
            // 获取“集合(c)”的数组,并将其赋值给elementData
            elementData = c.toArray();
            // 设置数组长度
            elementCount = elementData.length;
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
        }
    
        // 将数组Vector的全部元素都拷贝到数组anArray中
        public synchronized void copyInto(Object[] anArray) {
            System.arraycopy(elementData, 0, anArray, 0, elementCount);
        }
    
        // 将当前容量值设为 =实际元素个数
        public synchronized void trimToSize() {
            modCount++;
            int oldCapacity = elementData.length;
            if (elementCount < oldCapacity) {
                elementData = Arrays.copyOf(elementData, elementCount);
            }
        }
    
        // 确认“Vector容量”的帮助函数
        private void ensureCapacityHelper(int minCapacity) {
            int oldCapacity = elementData.length;
            // 当Vector的容量不足以容纳当前的全部元素,增加容量大小。
            // 若 容量增量系数>0(即capacityIncrement>0),则将容量增大当capacityIncrement
            // 否则,将容量增大一倍。
            if (minCapacity > oldCapacity) {
                Object[] oldData = elementData;
                int newCapacity = (capacityIncrement > 0) ?
                    (oldCapacity + capacityIncrement) : (oldCapacity * 2);
                if (newCapacity < minCapacity) {
                    newCapacity = minCapacity;
                }
                elementData = Arrays.copyOf(elementData, newCapacity);
            }
        }
    
        // 确定Vector的容量。
        public synchronized void ensureCapacity(int minCapacity) {
            // 将Vector的改变统计数+1
            modCount++;
            ensureCapacityHelper(minCapacity);
        }
    
        // 设置容量值为 newSize
        public synchronized void setSize(int newSize) {
            modCount++;
            if (newSize > elementCount) {
                // 若 "newSize 大于 Vector容量",则调整Vector的大小。
                ensureCapacityHelper(newSize);
            } else {
                // 若 "newSize 小于/等于 Vector容量",则将newSize位置开始的元素都设置为null
                for (int i = newSize ; i < elementCount ; i++) {
                    elementData[i] = null;
                }
            }
            elementCount = newSize;
        }
    
        // 返回“Vector的总的容量”
        public synchronized int capacity() {
            return elementData.length;
        }
    
        // 返回“Vector的实际大小”,即Vector中元素个数
        public synchronized int size() {
            return elementCount;
        }
    
        // 判断Vector是否为空
        public synchronized boolean isEmpty() {
            return elementCount == 0;
        }
    
        // 返回“Vector中全部元素对应的Enumeration”
        public Enumeration<E> elements() {
            // 通过匿名类实现Enumeration
            return new Enumeration<E>() {
                int count = 0;
    
                // 是否存在下一个元素
                public boolean hasMoreElements() {
                    return count < elementCount;
                }
    
                // 获取下一个元素
                public E nextElement() {
                    synchronized (Vector.this) {
                        if (count < elementCount) {
                            return (E)elementData[count++];
                        }
                    }
                    throw new NoSuchElementException("Vector Enumeration");
                }
            };
        }
    
        // 返回Vector中是否包含对象(o)
        public boolean contains(Object o) {
            return indexOf(o, 0) >= 0;
        }
    
    
        // 从index位置开始向后查找元素(o)。
        // 若找到,则返回元素的索引值;否则,返回-1
        public synchronized int indexOf(Object o, int index) {
            if (o == null) {
                // 若查找元素为null,则正向找出null元素,并返回它对应的序号
                for (int i = index ; i < elementCount ; i++)
                if (elementData[i]==null)
                    return i;
            } else {
                // 若查找元素不为null,则正向找出该元素,并返回它对应的序号
                for (int i = index ; i < elementCount ; i++)
                if (o.equals(elementData[i]))
                    return i;
            }
            return -1;
        }
    
        // 查找并返回元素(o)在Vector中的索引值
        public int indexOf(Object o) {
            return indexOf(o, 0);
        }
    
        // 从后向前查找元素(o)。并返回元素的索引
        public synchronized int lastIndexOf(Object o) {
            return lastIndexOf(o, elementCount-1);
        }
    
        // 从后向前查找元素(o)。开始位置是从前向后的第index个数;
        // 若找到,则返回元素的“索引值”;否则,返回-1。
        public synchronized int lastIndexOf(Object o, int index) {
            if (index >= elementCount)
                throw new IndexOutOfBoundsException(index + " >= "+ elementCount);
    
            if (o == null) {
                // 若查找元素为null,则反向找出null元素,并返回它对应的序号
                for (int i = index; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
            } else {
                // 若查找元素不为null,则反向找出该元素,并返回它对应的序号
                for (int i = index; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
            }
            return -1;
        }
    
        // 返回Vector中index位置的元素。
        // 若index月结,则抛出异常
        public synchronized E elementAt(int index) {
            if (index >= elementCount) {
                throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
            }
    
            return (E)elementData[index];
        }
    
        // 获取Vector中的第一个元素。
        // 若失败,则抛出异常!
        public synchronized E firstElement() {
            if (elementCount == 0) {
                throw new NoSuchElementException();
            }
            return (E)elementData[0];
        }
    
        // 获取Vector中的最后一个元素。
        // 若失败,则抛出异常!
        public synchronized E lastElement() {
            if (elementCount == 0) {
                throw new NoSuchElementException();
            }
            return (E)elementData[elementCount - 1];
        }
    
        // 设置index位置的元素值为obj
        public synchronized void setElementAt(E obj, int index) {
            if (index >= elementCount) {
                throw new ArrayIndexOutOfBoundsException(index + " >= " +
                                     elementCount);
            }
            elementData[index] = obj;
        }
    
        // 删除index位置的元素
        public synchronized void removeElementAt(int index) {
            modCount++;
            if (index >= elementCount) {
                throw new ArrayIndexOutOfBoundsException(index + " >= " +
                                     elementCount);
            } else if (index < 0) {
                throw new ArrayIndexOutOfBoundsException(index);
            }
    
            int j = elementCount - index - 1;
            if (j > 0) {
                System.arraycopy(elementData, index + 1, elementData, index, j);
            }
            elementCount--;
            elementData[elementCount] = null; /* to let gc do its work */
        }
    
        // 在index位置处插入元素(obj)
        public synchronized void insertElementAt(E obj, int index) {
            modCount++;
            if (index > elementCount) {
                throw new ArrayIndexOutOfBoundsException(index
                                     + " > " + elementCount);
            }
            ensureCapacityHelper(elementCount + 1);
            System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
            elementData[index] = obj;
            elementCount++;
        }
    
        // 将“元素obj”添加到Vector末尾
        public synchronized void addElement(E obj) {
            modCount++;
            ensureCapacityHelper(elementCount + 1);
            elementData[elementCount++] = obj;
        }
    
        // 在Vector中查找并删除元素obj。
        // 成功的话,返回true;否则,返回false。
        public synchronized boolean removeElement(Object obj) {
            modCount++;
            int i = indexOf(obj);
            if (i >= 0) {
                removeElementAt(i);
                return true;
            }
            return false;
        }
    
        // 删除Vector中的全部元素
        public synchronized void removeAllElements() {
            modCount++;
            // 将Vector中的全部元素设为null
            for (int i = 0; i < elementCount; i++)
                elementData[i] = null;
    
            elementCount = 0;
        }
    
        // 克隆函数
        public synchronized Object clone() {
            try {
                Vector<E> v = (Vector<E>) super.clone();
                // 将当前Vector的全部元素拷贝到v中
                v.elementData = Arrays.copyOf(elementData, elementCount);
                v.modCount = 0;
                return v;
            } catch (CloneNotSupportedException e) {
                // this shouldn't happen, since we are Cloneable
                throw new InternalError();
            }
        }
    
        // 返回Object数组
        public synchronized Object[] toArray() {
            return Arrays.copyOf(elementData, elementCount);
        }
    
        // 返回Vector的模板数组。所谓模板数组,即可以将T设为任意的数据类型
        public synchronized <T> T[] toArray(T[] a) {
            // 若数组a的大小 < Vector的元素个数;
            // 则新建一个T[]数组,数组大小是“Vector的元素个数”,并将“Vector”全部拷贝到新数组中
            if (a.length < elementCount)
                return (T[]) Arrays.copyOf(elementData, elementCount, a.getClass());
    
            // 若数组a的大小 >= Vector的元素个数;
            // 则将Vector的全部元素都拷贝到数组a中。
        System.arraycopy(elementData, 0, a, 0, elementCount);
    
            if (a.length > elementCount)
                a[elementCount] = null;
    
            return a;
        }
    
        // 获取index位置的元素
        public synchronized E get(int index) {
            if (index >= elementCount)
                throw new ArrayIndexOutOfBoundsException(index);
    
            return (E)elementData[index];
        }
    
        // 设置index位置的值为element。并返回index位置的原始值
        public synchronized E set(int index, E element) {
            if (index >= elementCount)
                throw new ArrayIndexOutOfBoundsException(index);
    
            Object oldValue = elementData[index];
            elementData[index] = element;
            return (E)oldValue;
        }
    
        // 将“元素e”添加到Vector最后。
        public synchronized boolean add(E e) {
            modCount++;
            ensureCapacityHelper(elementCount + 1);
            elementData[elementCount++] = e;
            return true;
        }
    
        // 删除Vector中的元素o
        public boolean remove(Object o) {
            return removeElement(o);
        }
    
        // 在index位置添加元素element
        public void add(int index, E element) {
            insertElementAt(element, index);
        }
    
        // 删除index位置的元素,并返回index位置的原始值
        public synchronized E remove(int index) {
            modCount++;
            if (index >= elementCount)
                throw new ArrayIndexOutOfBoundsException(index);
            Object oldValue = elementData[index];
    
            int numMoved = elementCount - index - 1;
            if (numMoved > 0)
                System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
            elementData[--elementCount] = null; // Let gc do its work
    
            return (E)oldValue;
        }
    
        // 清空Vector
        public void clear() {
            removeAllElements();
        }
    
        // 返回Vector是否包含集合c
        public synchronized boolean containsAll(Collection<?> c) {
            return super.containsAll(c);
        }
    
        // 将集合c添加到Vector中
        public synchronized boolean addAll(Collection<? extends E> c) {
            modCount++;
            Object[] a = c.toArray();
            int numNew = a.length;
            ensureCapacityHelper(elementCount + numNew);
            // 将集合c的全部元素拷贝到数组elementData中
            System.arraycopy(a, 0, elementData, elementCount, numNew);
            elementCount += numNew;
            return numNew != 0;
        }
    
        // 删除集合c的全部元素
        public synchronized boolean removeAll(Collection<?> c) {
            return super.removeAll(c);
        }
    
        // 删除“非集合c中的元素”
        public synchronized boolean retainAll(Collection<?> c)  {
            return super.retainAll(c);
        }
    
        // 从index位置开始,将集合c添加到Vector中
        public synchronized boolean addAll(int index, Collection<? extends E> c) {
            modCount++;
            if (index < 0 || index > elementCount)
                throw new ArrayIndexOutOfBoundsException(index);
    
            Object[] a = c.toArray();
            int numNew = a.length;
            ensureCapacityHelper(elementCount + numNew);
    
            int numMoved = elementCount - index;
            if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew, numMoved);
    
            System.arraycopy(a, 0, elementData, index, numNew);
            elementCount += numNew;
            return numNew != 0;
        }
    
        // 返回两个对象是否相等
        public synchronized boolean equals(Object o) {
            return super.equals(o);
        }
    
        // 计算哈希值
        public synchronized int hashCode() {
            return super.hashCode();
        }
    
        // 调用父类的toString()
        public synchronized String toString() {
            return super.toString();
        }
    
        // 获取Vector中fromIndex(包括)到toIndex(不包括)的子集
        public synchronized List<E> subList(int fromIndex, int toIndex) {
            return Collections.synchronizedList(super.subList(fromIndex, toIndex), this);
        }
    
        // 删除Vector中fromIndex到toIndex的元素
        protected synchronized void removeRange(int fromIndex, int toIndex) {
            modCount++;
            int numMoved = elementCount - toIndex;
            System.arraycopy(elementData, toIndex, elementData, fromIndex,
                             numMoved);
    
            // Let gc do its work
            int newElementCount = elementCount - (toIndex-fromIndex);
            while (elementCount != newElementCount)
                elementData[--elementCount] = null;
        }
    
        // java.io.Serializable的写入函数
        private synchronized void writeObject(java.io.ObjectOutputStream s)
            throws java.io.IOException {
            s.defaultWriteObject();
        }
    }
    View Code

      根据源码可以发现:Vector的底层数据结构和操作api大多与ArrayList一致,不同的地方在于:很多API都使用了 synchronized  关键字来保证线程安全

      也正是因为如此,所以Vector在多线程环境下效率比较慢,特别是查询操作也要被锁住,这很不友好。

      因此,不推荐使用Vector,而是使用CopyOnWriteArrayList类。

  • 相关阅读:
    bzoj 1017 魔兽地图DotR
    poj 1322 chocolate
    bzoj 1045 糖果传递
    poj 3067 japan
    timus 1109 Conference(二分图匹配)
    URAL 1205 By the Underground or by Foot?(SPFA)
    URAL 1242 Werewolf(DFS)
    timus 1033 Labyrinth(BFS)
    URAL 1208 Legendary Teams Contest(DFS)
    URAL 1930 Ivan's Car(BFS)
  • 原文地址:https://www.cnblogs.com/ygj0930/p/13560541.html
Copyright © 2011-2022 走看看