栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Vector的扩容机制,附源码解释

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Vector的扩容机制,附源码解释

1.简介

Vector是集合当中的一个重要知识点,它于ArrayList相比,最大的区别在于Vector是线程安全的,在源码当中的添加,删除等重要方法当中都加入了关键字 synchronized,实现了操作的线程安全,与ArrayList一样,Vector同样实现了 RandomAccess, Cloneable, Serializable接口。


2.Vector当中的字段

和ArrayList一样,我们先来对看jdk当中对Vevtor字段的定义,这有助于我们理解源码。

首先我们来看vector的定义字段,vector当中的字段不算很多,其中最重要的是理解elementData这个object类型的数组,一定要记住这个elementData是一个数组,而不是元素数据。这是vector乃至集合能够存储任何类型数据的原因,因为其底层是一个object类的数组。

public class Vectorextends AbstractList
    implements List, RandomAccess, Cloneable, java.io.Serializable{
   
    protected Object[] elementData;  
    //这是真正存数据的一个object类型的数组,这解释了为什么        
    //vector可以放任何类型的数据。

    protected int elementCount;
    //这里记录vector当中元素的个数,也就是elementDate这个数组当中的数组元素

    protected int capacityIncrement;
    //这是一个在扩容时用来判断的容量增量,默认为0(int类型数据默认为0)

   
    private static final long serialVersionUID = -2767605614048989439L;
    //这是一个序列号版本ID,用来判断类的,不用管他
}

 

 

Vector当中的扩容

当我们直接new一个vector时,如果不指定其初始容量大小,其会给一个默认大小为10的容量数组,如果你继续往下追,会发现,最后仍然会走到带参数的一个有参构造,所以结论:vector集合带参不带参最终都会走有参构造,区别是带的参数是你设置的还是jdk给你设置的。

  //这是无参构造
public Vector() {
        this(10);//给一个初始值,进入有参构造
    }

  //这是有参构造
public Vector(int initialCapacity) {  
        this(initialCapacity, 0);
    }

我们以jdk设置的默认大小为10的容量为例,对其扩容进行分析,为了尽量明了,我们这里就通过以下代码进行剖析:

public class vectorDetail {
   public static void main(String[] args) {

      Vector vector = new Vector();;
      //这里我创建了一个object类型的vector,
      //创建时如果不指定类型,默认为object,也就是我们上文说的elementData数组。

       for (int i = 0; i <11 ; i++) {
           vector.add(i);
       }
      //因为无参默认大小是10,我这里再加入第11个
      //元素(值为10,数组下标是从0开始)时必定会触发扩容机制。

   }

我们来具体看看,vector.add()方法到底长什么样?可以看到,add()方法被synchronized修饰着,这就是vector线程安全的根本原因,这里加了锁。此时很显然,我们的容量是不足够的,当前elementData数组空间已经被我们用完了,其elementData[ ]{0,1,2,3,4,5,6,7,8,9}现在是这么一个形式,已经把10大小的容量空间占完了,所以当我们要添加元素10时,必然会触发扩容。

 public synchronized boolean add(E e) {  //这是我们具体要添加的元素,
        modCount++;            //这是我们对集合修改的次数,不重要  
        ensureCapacityHelper(elementCount + 1);
        //这是判断我们当前vector集合当中的容量是否足够,
        //elementCount加一是我们当前所需要的最小容量

        elementData[elementCount++] = e; //将元素赋值给elementData数组
        return true;
    }

简单来看看ensureCapacityHelper(int minCapacity这个方法的代码,只要我们当前所需要的最小容量比数组的容量大就进行扩容grow()方法。

private void ensureCapacityHelper(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)  
            grow(minCapacity);
    }

今天的重头戏来了,我们来看看vector集合的扩容到底是如何实现的,可以看到vector底层是将原先的大小进行两倍扩容,然后返回给elementData。在方法内部真正实行扩容的是Arrays当中的一个静态方法。这个方法就是传入你一个原先的数组和一个你需要的空间大小,它帮你生成一个新的具有newCapacity大小的一个数组,然后将你原先数组当中的元素给拷贝到新的数组当中返回,这个方法的实现这里就不多赘述了,有兴趣的小伙伴也可以自己去看看源码。

 private void grow(int minCapacity) {

        int oldCapacity = elementData.length; //将原先的数组长度赋给oldCapacity
        int newCapacity = 
            oldCapacity + ((capacityIncrement > 0) ?capacityIncrement : oldCapacity);
        //三目运算符,因为我们的capacityIncrement默认等于0,在vector字段当中我有点出
        //因此我们的newCapacity=oldCapacity+oldCapacity,也就是原先长度的两倍
    
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;

        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);

        elementData = Arrays.copyOf(elementData, newCapacity);//这里进行真正的扩容。
    }

总结

Vector的扩容是比较简单粗暴的,直接两倍扩容,没有太多的弯弯绕绕和判断,在对线程安全有要求时,我们可以考虑使用vector。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1040702.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号