Article 21: Vector Source Analysis of JAVA Collections

Keywords: Java less JDK

Vector introduction

Vector is also based on arrays. It is a dynamic array whose capacity can grow automatically.

Vector is introduced by JDK 1.0, many of its implementation methods have added synchronization statements, so it is thread-safe (in fact, it is only relatively safe, sometimes it is necessary to add synchronization statements to ensure thread security), which can be used in multi-threaded environment.

Vector has no Serializable interface, so it does not support serialization, implements Cloneable interface, can be cloned, implements Random Access interface, and supports fast random access.


Vector Source Analysis

The source code for Vector is as follows (with more detailed comments added):

  1. package java.util;    
  2.    
  3. public class Vector<E>    
  4.     extends AbstractList<E>    
  5.     implements List<E>, RandomAccess, Cloneable, java.io.Serializable    
  6. {    
  7.        
  8.     //Array of data stored in Vector  
  9.     protected Object[] elementData;    
  10.    
  11.     //Number of actual data  
  12.     protected int elementCount;    
  13.    
  14.     //Capacity growth factor  
  15.     protected int capacityIncrement;    
  16.    
  17.     //Sequential version number of Vector  
  18.     private static final long serialVersionUID = -2767605614048989439L;    
  19.    
  20.     //Vector constructor. The default capacity is 10.     
  21.     public Vector() {    
  22.         this(10);    
  23.     }    
  24.    
  25.     //Constructor specifying the size of Vector capacity  
  26.     public Vector(int initialCapacity) {    
  27.         this(initialCapacity, 0);    
  28.     }    
  29.    
  30.     //Specify the constructor of Vector's "capacity size" and "growth factor"  
  31.     public Vector(int initialCapacity, int capacityIncrement) {    
  32.         super();    
  33.         if (initialCapacity < 0)    
  34.             throw new IllegalArgumentException("Illegal Capacity: "+    
  35.                                                initialCapacity);    
  36.         //Create a new array with initial capacity.  
  37.         this.elementData = new Object[initialCapacity];    
  38.         //Setting capacity growth factor  
  39.         this.capacityIncrement = capacityIncrement;    
  40.     }    
  41.    
  42.     //Specifies the Vector constructor for the collection.     
  43.     public Vector(Collection<? extends E> c) {    
  44.         //Get an array of sets (c) and assign it to elementData  
  45.         elementData = c.toArray();    
  46.         //Set the array length  
  47.         elementCount = elementData.length;    
  48.         // c.toArray might (incorrectly) not return Object[] (see 6260652)    
  49.         if (elementData.getClass() != Object[].class)    
  50.             elementData = Arrays.copyOf(elementData, elementCount, Object[].class);    
  51.     }    
  52.    
  53.     //Copy all elements of the array Vector into the array anArray.  
  54.     public synchronized void copyInto(Object[] anArray) {    
  55.         System.arraycopy(elementData, 0, anArray, 0, elementCount);    
  56.     }    
  57.    
  58.     //Set the current capacity value to = the number of actual elements  
  59.     public synchronized void trimToSize() {    
  60.         modCount++;    
  61.         int oldCapacity = elementData.length;    
  62.         if (elementCount < oldCapacity) {    
  63.             elementData = Arrays.copyOf(elementData, elementCount);    
  64.         }    
  65.     }    
  66.    
  67.     //Confirmation of the help function for Vector Capacity  
  68.     private void ensureCapacityHelper(int minCapacity) {    
  69.         int oldCapacity = elementData.length;    
  70.         //When Vector's capacity is insufficient to accommodate all the current elements, increase the capacity size.     
  71.         //If the capacity increment coefficient is greater than 0 (i.e. capacityIncrement > 0), the capacity will increase when capacityIncrement.  
  72.         //Otherwise, the capacity will be doubled.     
  73.         if (minCapacity > oldCapacity) {    
  74.             Object[] oldData = elementData;    
  75.             int newCapacity = (capacityIncrement > 0) ?    
  76.                 (oldCapacity + capacityIncrement) : (oldCapacity * 2);    
  77.             if (newCapacity < minCapacity) {    
  78.                 newCapacity = minCapacity;    
  79.             }    
  80.             elementData = Arrays.copyOf(elementData, newCapacity);    
  81.         }    
  82.     }    
  83.    
  84.     //Determine the capacity of Vector.     
  85.     public synchronized void ensureCapacity(int minCapacity) {    
  86.         //Change statistics of Vector + 1  
  87.         modCount++;    
  88.         ensureCapacityHelper(minCapacity);    
  89.     }    
  90.    
  91.     //Set the capacity value to newSize  
  92.     public synchronized void setSize(int newSize) {    
  93.         modCount++;    
  94.         if (newSize > elementCount) {    
  95.             //If "newSize" is larger than Vector capacity, adjust Vector size.     
  96.             ensureCapacityHelper(newSize);    
  97.         } else {    
  98.             //If "newSize" is less than/equal to Vector capacity, the elements starting at the newSize location are set to null.  
  99.             for (int i = newSize ; i < elementCount ; i++) {    
  100.                 elementData[i] = null;    
  101.             }    
  102.         }    
  103.         elementCount = newSize;    
  104.     }    
  105.    
  106.     //Return "Vector's total capacity"  
  107.     public synchronized int capacity() {    
  108.         return elementData.length;    
  109.     }    
  110.    
  111.     //Returns the actual size of the Vector, that is, the number of elements in the Vector.  
  112.     public synchronized int size() {    
  113.         return elementCount;    
  114.     }    
  115.    
  116.     //Judging whether Vector is empty  
  117.     public synchronized boolean isEmpty() {    
  118.         return elementCount == 0;    
  119.     }    
  120.    
  121.     //Return Enumeration for all elements in Vector  
  122.     public Enumeration<E> elements() {    
  123.         //Enumeration through anonymous classes  
  124.         return new Enumeration<E>() {    
  125.             int count = 0;    
  126.    
  127.             //Is there the next element?  
  128.             public boolean hasMoreElements() {    
  129.                 return count < elementCount;    
  130.             }    
  131.    
  132.             //Get the next element.  
  133.             public E nextElement() {    
  134.                 synchronized (Vector.this) {    
  135.                     if (count < elementCount) {    
  136.                         return (E)elementData[count++];    
  137.                     }    
  138.                 }    
  139.                 throw new NoSuchElementException("Vector Enumeration");    
  140.             }    
  141.         };    
  142.     }    
  143.    
  144.     //Returns whether the Vector contains an object (o)  
  145.     public boolean contains(Object o) {    
  146.         return indexOf(o, 0) >= 0;    
  147.     }    
  148.    
  149.    
  150.     //Look back at the element (o) from the index position.     
  151.     //If found, the index value of the element is returned; otherwise, return -1.  
  152.     public synchronized int indexOf(Object o, int index) {    
  153.         if (o == null) {    
  154.             //If the search element is null, the null element is found forward and its corresponding ordinal number is returned.  
  155.             for (int i = index ; i < elementCount ; i++)    
  156.             if (elementData[i]==null)    
  157.                 return i;    
  158.         } else {    
  159.             //If the element is not null, the element is found forward and its corresponding serial number is returned.  
  160.             for (int i = index ; i < elementCount ; i++)    
  161.             if (o.equals(elementData[i]))    
  162.                 return i;    
  163.         }    
  164.         return -1;    
  165.     }    
  166.    
  167.     //Find and return the index value of element (o) in Vector  
  168.     public int indexOf(Object o) {    
  169.         return indexOf(o, 0);    
  170.     }    
  171.    
  172.     //Look for elements (o) backwards and forwards. And return the index of the element.  
  173.     public synchronized int lastIndexOf(Object o) {    
  174.         return lastIndexOf(o, elementCount-1);    
  175.     }    
  176.    
  177.     //Look for elements (o) backwards and forwards. The starting position is the number of index es from the front to the back;  
  178.     //If found, return the "index value" of the element; otherwise, return - 1.     
  179.     public synchronized int lastIndexOf(Object o, int index) {    
  180.         if (index >= elementCount)    
  181.             throw new IndexOutOfBoundsException(index + " >= "+ elementCount);    
  182.    
  183.         if (o == null) {    
  184.             //If the finding element is null, the null element is retrieved and its corresponding serial number is returned.  
  185.             for (int i = index; i >= 0; i--)    
  186.             if (elementData[i]==null)    
  187.                 return i;    
  188.         } else {    
  189.             //If the element is not null, the element is retrieved and its corresponding serial number is returned.  
  190.             for (int i = index; i >= 0; i--)    
  191.             if (o.equals(elementData[i]))    
  192.                 return i;    
  193.         }    
  194.         return -1;    
  195.     }    
  196.    
  197.     //Returns the element at the index position in Vector.     
  198.     //If index ends, an exception is thrown.  
  199.     public synchronized E elementAt(int index) {    
  200.         if (index >= elementCount) {    
  201.             throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);    
  202.         }    
  203.    
  204.         return (E)elementData[index];    
  205.     }    
  206.    
  207.     //Get the first element in Vector.     
  208.     //If it fails, throw an exception!     
  209.     public synchronized E firstElement() {    
  210.         if (elementCount == 0) {    
  211.             throw new NoSuchElementException();    
  212.         }    
  213.         return (E)elementData[0];    
  214.     }    
  215.    
  216.     //Get the last element in Vector.     
  217.     //If it fails, throw an exception!     
  218.     public synchronized E lastElement() {    
  219.         if (elementCount == 0) {    
  220.             throw new NoSuchElementException();    
  221.         }    
  222.         return (E)elementData[elementCount - 1];    
  223.     }    
  224.    
  225.     //Set the element value of index position to obj  
  226.     public synchronized void setElementAt(E obj, int index) {    
  227.         if (index >= elementCount) {    
  228.             throw new ArrayIndexOutOfBoundsException(index + " >= " +    
  229.                                  elementCount);    
  230.         }    
  231.         elementData[index] = obj;    
  232.     }    
  233.    
  234.     //Delete the element in the index position  
  235.     public synchronized void removeElementAt(int index) {    
  236.         modCount++;    
  237.         if (index >= elementCount) {    
  238.             throw new ArrayIndexOutOfBoundsException(index + " >= " +    
  239.                                  elementCount);    
  240.         } else if (index < 0) {    
  241.             throw new ArrayIndexOutOfBoundsException(index);    
  242.         }    
  243.    
  244.         int j = elementCount - index - 1;    
  245.         if (j > 0) {    
  246.             System.arraycopy(elementData, index + 1, elementData, index, j);    
  247.         }    
  248.         elementCount--;    
  249.         elementData[elementCount] = null/* to let gc do its work */   
  250.     }    
  251.    
  252.     //Insert the element (obj) at the index position  
  253.     public synchronized void insertElementAt(E obj, int index) {    
  254.         modCount++;    
  255.         if (index > elementCount) {    
  256.             throw new ArrayIndexOutOfBoundsException(index    
  257.                                  + " > " + elementCount);    
  258.         }    
  259.         ensureCapacityHelper(elementCount + 1);    
  260.         System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);    
  261.         elementData[index] = obj;    
  262.         elementCount++;    
  263.     }    
  264.    
  265.     //Add "element obj" to the end of Vector  
  266.     public synchronized void addElement(E obj) {    
  267.         modCount++;    
  268.         ensureCapacityHelper(elementCount + 1);    
  269.         elementData[elementCount++] = obj;    
  270.     }    
  271.    
  272.     //Find and delete the element obj in Vector.     
  273.     //If successful, return true; otherwise, return false.     
  274.     public synchronized boolean removeElement(Object obj) {    
  275.         modCount++;    
  276.         int i = indexOf(obj);    
  277.         if (i >= 0) {    
  278.             removeElementAt(i);    
  279.             return true;    
  280.         }    
  281.         return false;    
  282.     }    
  283.    
  284.     //Delete all elements in Vector  
  285.     public synchronized void removeAllElements() {    
  286.         modCount++;    
  287.         //Set all elements in Vector to null  
  288.         for (int i = 0; i < elementCount; i++)    
  289.             elementData[i] = null;    
  290.    
  291.         elementCount = 0;    
  292.     }    
  293.    
  294.     //Clone function  
  295.     public synchronized Object clone() {    
  296.         try {    
  297.             Vector<E> v = (Vector<E>) super.clone();    
  298.             //Copy all elements of the current Vector into v.  
  299.             v.elementData = Arrays.copyOf(elementData, elementCount);    
  300.             v.modCount = 0;    
  301.             return v;    
  302.         } catch (CloneNotSupportedException e) {    
  303.             // this shouldn't happen, since we are Cloneable    
  304.             throw new InternalError();    
  305.         }    
  306.     }    
  307.    
  308.     //Returns the Object array.  
  309.     public synchronized Object[] toArray() {    
  310.         return Arrays.copyOf(elementData, elementCount);    
  311.     }    
  312.    
  313.     //Returns an array of templates for Vector. The so-called template array means that T can be set to any data type.  
  314.     public synchronized <T> T[] toArray(T[] a) {    
  315.         //If the size of array a is less than the number of elements of Vector;  
  316.         //Create a new T [] array with the size of "Number of Vector Elements" and copy all "Vector" into the new array.  
  317.         if (a.length < elementCount)    
  318.             return (T[]) Arrays.copyOf(elementData, elementCount, a.getClass());    
  319.    
  320.         //If the size of array a >= the number of elements of Vector;  
  321.         //Copy all elements of Vector into array a.     
  322.     System.arraycopy(elementData, 0, a, 0, elementCount);    
  323.    
  324.         if (a.length > elementCount)    
  325.             a[elementCount] = null;    
  326.    
  327.         return a;    
  328.     }    
  329.    
  330.     //Get the element at the index location  
  331.     public synchronized E get(int index) {    
  332.         if (index >= elementCount)    
  333.             throw new ArrayIndexOutOfBoundsException(index);    
  334.    
  335.         return (E)elementData[index];    
  336.     }    
  337.    
  338.     //Set the value of index to element. And returns the original value of the index position.  
  339.     public synchronized E set(int index, E element) {    
  340.         if (index >= elementCount)    
  341.             throw new ArrayIndexOutOfBoundsException(index);    
  342.    
  343.         Object oldValue = elementData[index];    
  344.         elementData[index] = element;    
  345.         return (E)oldValue;    
  346.     }    
  347.    
  348.     //Add "element e" to the end of Vector.     
  349.     public synchronized boolean add(E e) {    
  350.         modCount++;    
  351.         ensureCapacityHelper(elementCount + 1);    
  352.         elementData[elementCount++] = e;    
  353.         return true;    
  354.     }    
  355.    
  356.     //Delete element o in Vector  
  357.     public boolean remove(Object o) {    
  358.         return removeElement(o);    
  359.     }    
  360.    
  361.     //Add element at index position  
  362.     public void add(int index, E element) {    
  363.         insertElementAt(element, index);    
  364.     }    
  365.    
  366.     //Delete the element in the index position and return the original value of the index position.  
  367.     public synchronized E remove(int index) {    
  368.         modCount++;    
  369.         if (index >= elementCount)    
  370.             throw new ArrayIndexOutOfBoundsException(index);    
  371.         Object oldValue = elementData[index];    
  372.    
  373.         int numMoved = elementCount - index - 1;    
  374.         if (numMoved > 0)    
  375.             System.arraycopy(elementData, index+1, elementData, index,    
  376.                      numMoved);    
  377.         elementData[--elementCount] = null// Let gc do its work    
  378.    
  379.         return (E)oldValue;    
  380.     }    
  381.    
  382.     //Empty Vector  
  383.     public void clear() {    
  384.         removeAllElements();    
  385.     }    
  386.    
  387.     //Returns whether Vector contains collection c  
  388.     public synchronized boolean containsAll(Collection<?> c) {    
  389.         return super.containsAll(c);    
  390.     }    
  391.    
  392.     //Add collection c to Vector  
  393.     public synchronized boolean addAll(Collection<? extends E> c) {    
  394.         modCount++;    
  395.         Object[] a = c.toArray();    
  396.         int numNew = a.length;    
  397.         ensureCapacityHelper(elementCount + numNew);    
  398.         //Copy all elements of set c into the array elementData.  
  399.         System.arraycopy(a, 0, elementData, elementCount, numNew);    
  400.         elementCount += numNew;    
  401.         return numNew != 0;    
  402.     }    
  403.    
  404.     //Delete all elements of set c  
  405.     public synchronized boolean removeAll(Collection<?> c) {    
  406.         return super.removeAll(c);    
  407.     }    
  408.    
  409.     //Delete "Elements in non-set c"  
  410.     public synchronized boolean retainAll(Collection<?> c)  {    
  411.         return super.retainAll(c);    
  412.     }    
  413.    
  414.     //From the index location, add collection c to Vector.  
  415.     public synchronized boolean addAll(int index, Collection<? extends E> c) {    
  416.         modCount++;    
  417.         if (index < 0 || index > elementCount)    
  418.             throw new ArrayIndexOutOfBoundsException(index);    
  419.    
  420.         Object[] a = c.toArray();    
  421.         int numNew = a.length;    
  422.         ensureCapacityHelper(elementCount + numNew);    
  423.    
  424.         int numMoved = elementCount - index;    
  425.         if (numMoved > 0)    
  426.         System.arraycopy(elementData, index, elementData, index + numNew, numMoved);    
  427.    
  428.         System.arraycopy(a, 0, elementData, index, numNew);    
  429.         elementCount += numNew;    
  430.         return numNew != 0;    
  431.     }    
  432.    
  433.     //Returns whether two objects are equal.  
  434.     public synchronized boolean equals(Object o) {    
  435.         return super.equals(o);    
  436.     }    
  437.    
  438.     //Calculating hash values  
  439.     public synchronized int hashCode() {    
  440.         return super.hashCode();    
  441.     }    
  442.    
  443.     //Call toString() of the parent class  
  444.     public synchronized String toString() {    
  445.         return super.toString();    
  446.     }    
  447.    
  448.     //Get a subset of fromIndex (including) to toIndex (excluding) in Vector.  
  449.     public synchronized List<E> subList(int fromIndex, int toIndex) {    
  450.         return Collections.synchronizedList(super.subList(fromIndex, toIndex), this);    
  451.     }    
  452.    
  453.     //Delete elements from fromIndex to toIndex in Vector  
  454.     protected synchronized void removeRange(int fromIndex, int toIndex) {    
  455.         modCount++;    
  456.         int numMoved = elementCount - toIndex;    
  457.         System.arraycopy(elementData, toIndex, elementData, fromIndex,    
  458.                          numMoved);    
  459.    
  460.         // Let gc do its work    
  461.         int newElementCount = elementCount - (toIndex-fromIndex);    
  462.         while (elementCount != newElementCount)    
  463.             elementData[--elementCount] = null;    
  464.     }    
  465.    
  466.     //Write function of java.io.Serializable  
  467.     private synchronized void writeObject(java.io.ObjectOutputStream s)    
  468.         throws java.io.IOException {    
  469.         s.defaultWriteObject();    
  470.     }    
  471. }   

Summary

Vector's source code implementation is similar to ArrayList in general. The following summaries are given about Vector's source code:

Vector has four different construction methods. The capacity of the parametric construction method is the default value of 10, while the capacity-only construction method sets the capacity growth (the role of capacity growth can be seen from the source code, and the second point will be more detailed about capacity growth) as 0.

2. Pay attention to the method of capacity expansion to ensure Capacity Helper. Like ArrayList, Vector calls this method every time it adds elements (maybe one or a group) to ensure adequate capacity. When the capacity is not enough to accommodate the current number of elements, we first look at whether the parameter Capacity Increment is 0. If it is not 0, we set the new capacity as the capacity plus the capacity growth. If it is 0, we set the new capacity as twice the old capacity. If the new capacity is not enough, we set the new capacity as the input parameter directly. (that is, the required capacity) and then copy the elements to the new array using the Arrays.copyof() method as well.

3. Many methods add synchronized synchronized statements to ensure thread safety.

4. Similarly, in the method of finding the index value of a given element, the source code divides the value of the element into null and non-null cases, and the element is allowed to be null in Vector.

5. Many other places are similar to ArrayList implementations, and Vector is now largely out of use.  

Posted by mcloan on Tue, 04 Jun 2019 14:53:37 -0700