• Vector源码分析


    简介

    Vector是JDK1.0版本添加的类,以数组为底层数据结构的集合,也是一个动态的数组队列

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

    该类继承的了AbstractList,本质是一个List,具有添删改查等功能。

    实现接口:

    • List
    • RandomAccess:具有随机访问的功能。
    • Cloneable:具有克隆的功能。
    • java.io.Serializable:具有反序列化的功能。

    Vector与ArrayList的区别就是Vactor支持线程同步,而ArrayList不支持。


    API

    synchronized boolean        add(E object)
                 void           add(int location, E object)
    synchronized boolean        addAll(Collection<? extends E> collection)
    synchronized boolean        addAll(int location, Collection<? extends E> collection)
    synchronized void           addElement(E object)
    synchronized int            capacity()
                 void           clear()
    synchronized Object         clone()
                 boolean        contains(Object object)
    synchronized boolean        containsAll(Collection<?> collection)
    synchronized void           copyInto(Object[] elements)
    synchronized E              elementAt(int location)
                 Enumeration<E> elements()
    synchronized void           ensureCapacity(int minimumCapacity)
    synchronized boolean        equals(Object object)
    synchronized E              firstElement()
                 E              get(int location)
    synchronized int            hashCode()
    synchronized int            indexOf(Object object, int location)
                 int            indexOf(Object object)
    synchronized void           insertElementAt(E object, int location)
    synchronized boolean        isEmpty()
    synchronized E              lastElement()
    synchronized int            lastIndexOf(Object object, int location)
    synchronized int            lastIndexOf(Object object)
    synchronized E              remove(int location)
                 boolean        remove(Object object)
    synchronized boolean        removeAll(Collection<?> collection)
    synchronized void           removeAllElements()
    synchronized boolean        removeElement(Object object)
    synchronized void           removeElementAt(int location)
    synchronized boolean        retainAll(Collection<?> collection)
    synchronized E              set(int location, E object)
    synchronized void           setElementAt(E object, int location)
    synchronized void           setSize(int length)
    synchronized int            size()
    synchronized List<E>        subList(int start, int end)
    synchronized <T> T[]        toArray(T[] contents)
    synchronized Object[]       toArray()
    synchronized String         toString()
    synchronized void           trimToSize()
    

    属性

    //容器数据结构
    protected Object[] elementData;
    
    //实际数据大小
    protected int elementCount;
    
    //容器增长数据
    protected int capacityIncrement;
    
    //序列化版本ID
    private static final long serialVersionUID = -2767605614048989439L;
    
    //数组最大长度
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    

    MAX_ARRAY_SIZE为什么不是Integer.MAX_VALUE而是Integer.MAX_VALUE-8呢,原因是数组需要8个字节存储数组长度。

    构造函数:

    //无参构造函数,默认10大小容量
    public Vector() {
      this(10);
    }
    
    //制定容器大小容量,但容器增长系数为0
    public Vector(int initialCapacity) {
      this(initialCapacity, 0);
    }
    
    //最终调用的构造函数,制定容器大小和容器增长系数,且为饿汉模式。
    public Vector(int initialCapacity, int capacityIncrement) {
      super();
      if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
      this.elementData = new Object[initialCapacity];
      this.capacityIncrement = capacityIncrement;
    }
    
    //创建一个包含Collection容器数据的Vector容器
    public Vector(Collection<? extends E> c) {
      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);
    }
    

    源代码分析(JDK1.8)

    //复制容器数据到anArray数组中
    public synchronized void copyInto(Object[] anArray) {
    	System.arraycopy(elementData, 0, anArray, 0, elementCount);
    }
    
    
    //去除容器不存储数据的空间。(即容器数据大小等于elementCount)
    public synchronized void trimToSize() {
      modCount++;
      int oldCapacity = elementData.length;
      if (elementCount < oldCapacity) {
      elementData = Arrays.copyOf(elementData, elementCount);
      }
    }
    
    
    //确定容器容量是否合法
    public synchronized void ensureCapacity(int minCapacity) {
      if (minCapacity > 0) {
        modCount++;
        ensureCapacityHelper(minCapacity);
      }
    }
    
    
    //确定容器是否需要扩容
    private void ensureCapacityHelper(int minCapacity) {
      // overflow-conscious code
      if (minCapacity - elementData.length > 0)
        grow(minCapacity);
    }
    
    
    //扩容函数
    private void grow(int minCapacity) {
      int oldCapacity = elementData.length;
      //这里两种情况,若capacityIncrement<=0,即增长2倍,capacityIncrement>0,增长oldCapacity+capacityIncrement。
      int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                       capacityIncrement : oldCapacity);
      if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
      //超过该容器最大长度,调用hugeCapacity重新计算新容量。
      if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
      
      //扩容
      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;
    }
    
    
    //重新确定容器数据的容量,超过数据容量则丢弃。
    public synchronized void setSize(int newSize) {
      modCount++;
      if (newSize > elementCount) {
        ensureCapacityHelper(newSize);
      } else {
        for (int i = newSize ; i < elementCount ; i++) {
          elementData[i] = null;
        }
      }
      elementCount = newSize;
    }
    
    
    //获取容器大小
    public synchronized int capacity() {
      return elementData.length;
    }
    
    
    //获取容器数据大小
    public synchronized int size() {
      return elementCount;
    }
    
    
    //检测容器是否没有数据
    public synchronized boolean isEmpty() {
      return elementCount == 0;
    }
    
    
    //返回一个Enumeration组件,用于来遍历容器
    public Enumeration<E> elements() {
      return new Enumeration<E>() {
        //遍历索引 = 0
        int count = 0;
    		//判断是否还有元素
        public boolean hasMoreElements() {
          return count < elementCount;
        }
    		//获取当前索引,之后++
        public E nextElement() {
          synchronized (Vector.this) {
            if (count < elementCount) {
              return elementData(count++);
            }
          }
          throw new NoSuchElementException("Vector Enumeration");
        }
      };
    }
    
    
    //判断是否存在指定的数据
    public boolean contains(Object o) {
      return indexOf(o, 0) >= 0;
    }
    
    
    //正向获取指定数据(Object o)第一个出现的索引
    public int indexOf(Object o) {
      return indexOf(o, 0);
    }
    
    
    //从index索引向后查找数据(Object o)的第一次出现的索引。
    //查找到则返回该索引,查找不到则返回-1。
    public synchronized int indexOf(Object o, int index) {
      //正向查找数据为null的索引
      if (o == 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;
      }
      //查找不到则返回-1;
      return -1;
    }
    
    //反向获取指定数据(Object o)第一个出现的索引
    public synchronized int lastIndexOf(Object o) {
      return lastIndexOf(o, elementCount-1);
    }
    
    
    //从index索引向前查找数据(Object o)的第一次出现的索引。
    //查找到则返回该索引,查找不到则返回-1。
    public synchronized int lastIndexOf(Object o, int index) {
      //判断查找起点是不是非法
      if (index >= elementCount)
        throw new IndexOutOfBoundsException(index + " >= "+ elementCount);
    	//反向查找数据为null的索引
      if (o == 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;
      }
      //查找不到则返回-1;
      return -1;
    }
    
    //获取指定索引的对象
    public synchronized E elementAt(int index) {
      //判断索引位置是不是非法
      if (index >= elementCount) {
        throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
      }
      return elementData(index);
    }
    
    
    //获取容器第一个的数据
    public synchronized E firstElement() {
      //若容器数据容量为0则抛出NoSuchElementException
      if (elementCount == 0) {
        throw new NoSuchElementException();
      }
      return elementData(0);
    }
    
    
    //获取容器最后一个的数据
    public synchronized E lastElement() {
      if (elementCount == 0) {
        throw new NoSuchElementException();
      }
      return 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++;
      //移除容器的位置超出数据容量大小,抛出ArrayIndexOutOfBoundsException
      if (index >= elementCount) {
        throw new ArrayIndexOutOfBoundsException(index + " >= " +
                                                 elementCount);
      }
      else if (index < 0) {//移除容器的位置不合法,抛出ArrayIndexOutOfBoundsException
        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插入新数据
    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);//index后面数据需要移动一位。
      elementData[index] = obj;
      elementCount++;
    }
    
    //添加数据
    public synchronized void addElement(E obj) {
      modCount++;
      //确定容器是否需要扩容
      ensureCapacityHelper(elementCount + 1);
      //往容器数据最后位置添加
      elementData[elementCount++] = obj;
    }
    
    
    //移除指定的数据,删除成功返回true,删除失败返回false。
    public synchronized boolean removeElement(Object obj) {
      modCount++;
      //正向获取数据第一次出现的索引。
      int i = indexOf(obj);
      if (i >= 0) {
        removeElementAt(i);
        return true;
      }
      return false;
    }
    
    
    //移除所有数据
    public synchronized void removeAllElements() {
      modCount++;
      // Let gc do its work
      for (int i = 0; i < elementCount; i++)
        elementData[i] = null;
    	//重置数据容量大小
      elementCount = 0;
    }
    
    
    //克隆容器函数(浅克隆)
    public synchronized Object clone() {
      try {
        @SuppressWarnings("unchecked")
        Vector<E> v = (Vector<E>) super.clone();
        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(e);
      }
    }
    
    
    //获取数据容器副本。
    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;
    }
    
    
    //获取指定索引上的数据
    public synchronized E get(int index) {
      if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index);
    
      return elementData(index);
    }
    
    
    //更改索引index上的数据,替换为element,并返回旧数据。
    public synchronized E set(int index, E element) {
      if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index);
    
      E oldValue = elementData(index);
      elementData[index] = element;
      return oldValue;
    }
    
    //添加在数据容器最后添加数据
    public synchronized boolean add(E e) {
      modCount++;
      ensureCapacityHelper(elementCount + 1);
      elementData[elementCount++] = e;
      return true;
    }
    
    
    //移除指定数据(第一次出现的位置)
    public boolean remove(Object o) {
      return removeElement(o);
    }
    
    
    
    //移除指定索引的数据,并返回移除的数据。
    public synchronized E remove(int index) {
      modCount++;
      if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index);
      E 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 oldValue;
    }
    
    
    //移除所有数据
    public void clear() {
      removeAllElements();
    }
    
    
    // 删除集合c的全部元素
    public synchronized boolean removeAll(Collection<?> c) {
      return super.removeAll(c);
    }
    
    
    // 删除“非集合c中的元素”
    public synchronized boolean retainAll(Collection<?> c)  {
      return super.retainAll(c);
    }
    
    
    // 在指定索引后将集合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);//把索引移动numNew位,就是腾出位置给新数据
    
      System.arraycopy(a, 0, elementData, index, numNew);//添加新数据
      elementCount += numNew;//更改数据容器大小
      return numNew != 0;//若要添加容器c有数据则返回true,没有数据返回false;
    }
    
    
    // 返回两个对象是否相等
    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();
    }
    
    
    //移除一个范围内(fromIndex-toIndex)的数据
    protected synchronized void removeRange(int fromIndex, int toIndex) {
      modCount++;
      int numMoved = elementCount - toIndex;//toIndex索引后面需要保留的数据
      System.arraycopy(elementData, toIndex, elementData, fromIndex,
                       numMoved);//需要保留的数据往前移动,覆盖删除部分。
    
      // Let gc do its work
      int newElementCount = elementCount - (toIndex-fromIndex);//重新计算数据容量大小
      while (elementCount != newElementCount)
        elementData[--elementCount] = null;
    }
    
    //对Vector容器中属性进行写入写出操作。	
    private void readObject(ObjectInputStream in)
      throws IOException, ClassNotFoundException {
      ObjectInputStream.GetField gfields = in.readFields();
      int count = gfields.get("elementCount", 0);
      Object[] data = (Object[])gfields.get("elementData", null);
      if (count < 0 || data == null || count > data.length) {
        throw new StreamCorruptedException("Inconsistent vector internals");
      }
      elementCount = count;
      elementData = data.clone();
    }
    private void writeObject(java.io.ObjectOutputStream s)
      throws java.io.IOException {
      final java.io.ObjectOutputStream.PutField fields = s.putFields();
      final Object[] data;
      synchronized (this) {
        fields.put("capacityIncrement", capacityIncrement);
        fields.put("elementCount", elementCount);
        data = elementData.clone();
      }
      fields.put("elementData", data);
      s.writeFields();
    }
    

    Vector容器遍历方式

    遍历方式有四种

    • 使用迭代器

      List<Integer> vector = new Vector<Integer>(5);
      vector.add(1);
      vector.add(2);
      vector.add(3);
      vector.add(4);
      vector.add(5);
      Iterator<Integer> iterator = vector.iterator();
      while (iterator.hasNext()){
        System.out.println(iterator.next());
      }
      
    • 使用索引值

      int size = vector.size();
      for(int i = 0; i<size; i++){
        System.out.println(vector.get(i));
      }
      
    • for循环

      Integer value = null;
      for (Integer i:vector) {
          System.out.println(i);
      }
      
    • Enumeration遍历

      Vector<Integer> vector = new Vector<Integer>(5);
      vector.add(1);
      vector.add(2);
      vector.add(3);
      vector.add(4);
      vector.add(5);
      Enumeration<Integer> elements = vector.elements();
      while (elements.hasMoreElements()){
        System.out.println(elements.nextElement());
      }
      

    提示:

    当扩容超过MAX_ARRAY_SIZE会导致错误。官方文档有对这个解释

      /**
        * The maximum size of array to allocate.
        * Some VMs reserve some header words in an array.
        * Attempts to allocate larger arrays may result in
        * OutOfMemoryError: Requested array size exceeds VM limit
        */
    

    意思是如果数组长度过大,会导致OutOfMemoryError错误

    这个问题导致OutOfMemoryError有两种可能:

    • **OutOfMemoryError: Java heap space **堆内存空间不足(这个可以通过设置JVM参数 -Xmx 来指定)。
    • **OutOfMemoryError: Requested array size exceeds VM limit **超过JVM虚拟机的最大限制。
  • 相关阅读:
    【转载】数据杂谈
    【转载】行走在网格之间:微博用户关系模型
    【转载】TalkingData首席金融行业专家鲍忠铁:18亿数据解读移动互联网
    【转载】大数据架构和模式
    【转载】Deep Learning(深度学习)学习笔记整理
    【转载】如何组建一支优秀的数据分析团队?
    【转载】Hadoop可视化分析利器之Hue
    【转载】关于烂代码的那些事
    【转载】6个用好大数据的秘诀
    【转载】如何一步步从数据产品菜鸟走到骨干数据产品
  • 原文地址:https://www.cnblogs.com/zitai/p/13061313.html
Copyright © 2020-2023  润新知