• Java 集合:(七) List实现类:Vector


    一、Vector 概述

      1、Vector 是 List 接口的另一个实现类: Vector

      2、Vector 是一个古老的集合,JDK1.0就有了。大多数操作与ArrayList相同,区别之处在于Vector是线程安全的。 

      3、Vector 的内部实现与 ArrayList 类似,也可以理解为一个【可变数组】。

        其继承结构如下:
        

      4、由于 Vector 目前使用较少,且官方也推荐在无线程安全的需求时使用 ArrayList 代替 Vector,这里仅研究其实现原理。

        stackoverflow 也有相关的讨论:

     

    二、实现的接口

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

        可以发现,Vector 实现的接口同 ArrayList,作用也是一致的。

    三、成员变量

     1     /**
     2      * The array buffer into which the components of the vector are
     3      * stored. The capacity of the vector is the length of this array buffer,
     4      * and is at least large enough to contain all the vector's elements.
     5      *
     6      * <p>Any array elements following the last element in the Vector are null.
     7      *
     8      * @serial
     9      */
    10     protected Object[] elementData;  //存储数据的数组
    11 
    12     /**
    13      * The number of valid components in this {@code Vector} object.
    14      * Components {@code elementData[0]} through
    15      * {@code elementData[elementCount-1]} are the actual items.
    16      *
    17      * @serial
    18      */
    19     protected int elementCount;     //有效元素的个数
    20 
    21     /**
    22      * The amount by which the capacity of the vector is automatically
    23      * incremented when its size becomes greater than its capacity.  If
    24      * the capacity increment is less than or equal to zero, the capacity
    25      * of the vector is doubled each time it needs to grow.
    26      *
    27      * @serial
    28      */
    29     protected int capacityIncrement;   //容量增长因子
    30 
    31     /** use serialVersionUID from JDK 1.0.2 for interoperability */
    32     private static final long serialVersionUID = -2767605614048989439L;
    33     
    34         /**
    35      * The maximum size of array to allocate.
    36      * Some VMs reserve some header words in an array.
    37      * Attempts to allocate larger arrays may result in
    38      * OutOfMemoryError: Requested array size exceeds VM limit
    39      */
    40     private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    四、构造器

      Vector 对外提供四个构造器(内部可以认为是两个)

      1、方式一:

     1 protected Object[] elementData;
     2 
     3 protected int capacityIncrement;
     4 
     5 // 无参构造器
     6 public Vector() {
     7     this(10);
     8 }
     9 
    10 // 指定容量的构造器
    11 public Vector(int initialCapacity) {
    12     this(initialCapacity, 0);
    13 }
    14 
    15 // 指定初始容量和容量增长因子的构造器
    16 public Vector(int initialCapacity, int capacityIncrement) {
    17     super();
    18     if (initialCapacity < 0)
    19         throw new IllegalArgumentException("Illegal Capacity: "+
    20                                            initialCapacity);
    21     this.elementData = new Object[initialCapacity];
    22     this.capacityIncrement = capacityIncrement;
    23 }   
        与 ArrayList 类似,Vector 内部也维护了一个 Object 类型的数组(elementData)来存储元素(默认初始容量也是10)。
        不同的是:Vector 比 ArrayList 的构造器多了一个参数 capacityIncrement,该变量也导致了二者的扩容方式略有不同。

      2、方式二:入参为集合的构造器

    1     public Vector(Collection<? extends E> c) {
    2         Object[] a = c.toArray();
    3         elementCount = a.length;
    4         if (c.getClass() == ArrayList.class) {
    5             elementData = a;
    6         } else {
    7             elementData = Arrays.copyOf(a, elementCount, Object[].class);
    8         }
    9     }

    五、Vector 扩容原理分析

      1、从构造函数分析

        (1)从上面构造器可以发现以无参数构造方法创建 Vector 时,实际上初始化赋值的是一个容量为10的数组,扩容因子是0

        (2)还可以指定容量,就会创建一个容量为指定的数组,此时的数组扩容因子是 0

        (3)也可以同时指定容量和扩容因子,会创建一个指定容量的数组,扩容因子为设置的值。

        

      2、一步一步分析 Vector 扩容机制

        这里以无参构造函数创建的 ArrayList 为例分析

        (1)先来看 add 方法(addAll()方法类似)

     1     /**
     2      * 将指定的元素追加到此列表的末尾。
     3      */
     4     public synchronized boolean add(E e) {
     5         //添加元素之前,先调用ensureCapacityHelper方法
     6         modCount++;
     7         ensureCapacityHelper(elementCount + 1);   //确保内部容量
     8         //这里看到ArrayList添加元素的实质就相当于为数组赋值
     9         elementData[elementCount++] = e;
    10         return true;
    11     }

           可以看到,在 add() 方法执行时,会首先执行  ensureCapacityHelper 方法

           注意这里的关键字 synchronized。观察可以发现:Vector 内部许多方法都使用了该关键字,这也是 Vector 实现线程安全的方式,简单粗暴!

        (2)查看 ensureCapacityHelper() 方法

          该方法是非同步的,因为 Vector 内部调用该方法的地方都使用了 synchronized 关键字进行同步,这里不再额外使用

    1     private void ensureCapacityHelper(int minCapacity) {
    2         // overflow-conscious code
    3         //判断是否需要扩容,如果所需容量大于目前数组长度,则进行扩容
    4         if (minCapacity - elementData.length > 0)
    5             grow(minCapacity);
    6     }

        (3)grow()方法

          源码:

     1     /**
     2      * Vector 扩容的核心方法。
     3      */
     4     private void grow(int minCapacity) {
     5         // overflow-conscious code
     6         // oldCapacity为旧容量,newCapacity为新容量
     7         int oldCapacity = elementData.length;
     8         
     9         //如果指定了扩容因子 capacityIncrement,则在原来容量上扩容
    10         //如果没有指定扩容因子,则扩容为2倍容量
    11         int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
    12                                          capacityIncrement : oldCapacity);
    13                                          
    14         //然后检查新容量是否大于最小需要容量,若还是小于最小需要容量,那么就把最小需要容量当作数组的新容量,
    15         if (newCapacity - minCapacity < 0)
    16             newCapacity = minCapacity;
    17             
    18         // 如果新容量大于 MAX_ARRAY_SIZE,进入(执行) hugeCapacity() 方法来比较 minCapacity 和 MAX_ARRAY_SIZE,    
    19         //如果minCapacity大于最大容量,则新容量则为Integer.MAX_VALUE,否则,新容量大小则为 MAX_ARRAY_SIZE 即为Integer.MAX_VALUE - 8。
    20         if (newCapacity - MAX_ARRAY_SIZE > 0)
    21             newCapacity = hugeCapacity(minCapacity);
    22         elementData = Arrays.copyOf(elementData, newCapacity);
    23     }

          从这里可以看出,Vector 与 ArrayList 的扩容方式基本一致,只是新容量的计算方式有所不同,这里分析下其新容量大小:

    int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
        Vector 计算扩容后的新容量时,根据 capacityIncrement 的值可以分为两种情况:
        1. capacityIncrement > 0:新容量 = 旧容量 + capacityIncrement;
        2. capacityIncrement <= 0:新容量 = 旧容量 * 2。

     

        (4)hugeCapacity()方法(巨大的容量)

          从上面 grow() 方法源码我们知道: 如果新容量大于 MAX_ARRAY_SIZE,进入(执行) hugeCapacity() 方法来比较 minCapacity 和 MAX_ARRAY_SIZE,如果 minCapacity 大于最大容量,则新容量则为Integer.MAX_VALUE,否则,新容量大小则为 MAX_ARRAY_SIZE 即为 Integer.MAX_VALUE - 8

    1 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    2 
    3 private static int hugeCapacity(int minCapacity) {
    4     if (minCapacity < 0) // overflow
    5         throw new OutOfMemoryError();
    6     return (minCapacity > MAX_ARRAY_SIZE) ?
    7         Integer.MAX_VALUE :
    8         MAX_ARRAY_SIZE;
    9 }

      3、

      4、

      5、

    六、常用方法

      Vector 与 ArrayList 常用方法几乎类似,只是在方面上面添加了 synchronized 关键字来保证同步,因此性能比较差。

      在各种list中,最好把ArrayList作为缺省选择。当插入、删除频繁时,使用LinkedList;Vector总是比ArrayList慢,所以尽量避免使用。

    七、线程安全性

      Vector 是线程安全的,它实现线程安全的方式也很简单粗暴:直接在方法上使用 synchronized 关键字进行同步。

    八、总结

      1、与 ArrayList 类似,Vector 也可以认为是【可变数组】;
      2、扩容原理与 ArrayList 基本一致,只是新容量计算方式略有不同;指定增长容量时,新容量为 旧容量 + 增长容量;否则扩容为旧容量的 两倍。
      3、线程安全的,实现方式简单(synchronized)

    九、

    十、

  • 相关阅读:
    对于Python中self的看法
    SpringBoot整合MyBatis-Plus快速开始
    Hive原理--体系结构
    Docker Compose + Traefik v2 快速安装, 自动申请SSL证书 http转https 初次尝试
    记录:更新VS2019后单元测试运行卡住无法运行测试的问题。
    黑帽来源页劫持代码以及如何防范
    OFFICE 2010 每次打开提示安装的问题
    Mssql 查询某记录前后N条
    验证邮箱正则表达式,包含二级域名邮箱,手机号正则表达式支持170号段
    删除TFS上的团队项目
  • 原文地址:https://www.cnblogs.com/niujifei/p/14675812.html
Copyright © 2020-2023  润新知