• 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类。

  • 相关阅读:
    HDU 1078 FatMouse and Cheese (简单DP)
    HDU 1052 Tian Ji The Horse Racing (贪心)
    HDU 4432 Sum of divisors 第37届ACM/ICPC天津现场赛B题 (简单题)
    HDU 1079 Calendar Game (博弈)
    HDU 4438 Hunters 第37届ACM/ICPC 天津赛区现场赛H题(超级水的题目)
    php级联
    C++运算符重载
    C++循环语句
    C++类复制构造函数
    C++ struct,union和enum
  • 原文地址:https://www.cnblogs.com/ygj0930/p/13560541.html
Copyright © 2020-2023  润新知