Vector源码解析

更多内容参考

1.Vector前导

1.1继承体系

在这里插入图片描述

1.2简单概述

Vector是一个古老的线程安全(内部的核心方法都加了synchronized)的容器,在JDK1.0时就已经存在,到如今已经很少使用。基本结构与ArrayList类似,可以认为是线程安全版本的ArrayList,但因为Vector效率低下,所以在多线程下使用的基本都是 CopyOnWriteArrayList() 其效率更高。

2.核心结构

2.1属性

    //底层存储数据的数组
	protected Object[] elementData;
	
    //数组中的元素个数
    protected int elementCount;
	
    /*
     * 扩容时指定扩容的容量(>0),即扩容后的容量为 oldCap + capacityIncrement
     * 若没有指定,那么默认扩容为原容量的2倍,即扩容后的容量为 2 * oldCap
     */
    protected int capacityIncrement;

2.2构造器

调用无参构造器时,默认初始化容量为10

// ------------------------------ 构造器1 ------------------------------------
	
	/*
     *   传入初始容量和扩容数量
     *    这里跟ArrayList不同的是,Vector是非懒加载的,调用构造器就会
     *    初始化数组
     */
	public Vector(int initialCapacity, int capacityIncrement) {	
        //判断初始容量是否合法
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        //直接构造数组赋值给内部的elementData。
        this.elementData = new Object[initialCapacity];
        //传入的扩容数量赋值给capacityIncrement
        this.capacityIncrement = capacityIncrement;
    }
	
// ------------------------------ 构造器2 -------------------------------------

	/*
	 * 调用是构造器1,只是扩容数量传入的是0,即扩容时默认扩容为原长度的2倍。
	 *
	 */
    public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }

// ------------------------------ 构造器3 -------------------------------------

	/*
	 *  底层调用构造器2. 默认初始化长度为10. capacityIncrement为0.
	 */
    public Vector() {
        this(10);
    }

3.核心方法

3.1add()

  	/*
  	 *  加锁方法,线程安全。 
  	 */
	public synchronized boolean add(E e) {
        modCount++;
        add(e, elementData, elementCount);
        return true;
    }

//              ||    
//  		    ||
// 				\/
	
	/*
	 *  @param e 添加的元素
	 *  @param elementData 内部数组 
	 *  @param s 元素个数
	 */
    private void add(E e, Object[] elementData, int s) {
        //判断元素个数等于数组长度,下面是扩容的逻辑
        if (s == elementData.length)
            elementData = grow();
        //s就是待插入的位置,将e放到集合中
        elementData[s] = e;
        //元素个数+1
        elementCount = s + 1;
    }

3.2*grow()/newCapacity()

    /*
     *  调用了重载的带参数的grow(int minCapacity)方法
     */
	private Object[] grow() {
        return grow(elementCount + 1);
    }
	
	
//              ||    
//  		    ||
// 				\/

	/*
	 *  1.首先调用newCapacity()方法,计算出扩容后数组的容量x
	 *  2.然后调用Arrays.copyOf()方法重新创建一个长度为x的数组,然后将
	 *    原数组中的数据拷贝过去。完成扩容操作
	 * 
	 *   @param minCapacity 当前数组需要存放的元素的个数(即所需要的长度)
	 */
	private Object[] grow(int minCapacity) {
        return elementData = Arrays.copyOf(elementData,
                                           newCapacity(minCapacity));
    }

newCapacity()

扩容大致流程

这里只关注普通情况,因为一般一个集合中的元素个数不会达到INF级别。

  • capacityIncrement大于0 时,newCap = oldCap + capacityIncrement
  • 否则 newCap = oldCap * 2
    /*
     * 计算出最终扩容后的数组长度。
     */
	private int newCapacity(int minCapacity) {
        //获取当前数组长度
        int oldCapacity = elementData.length;
        
        /*
         * 这里就是计算扩容后的长度的核心。
         *   1.首先判断capacityIncrement是否大于0,如果大于0,那么这次扩容的长度为
         *   oldCapacity + capacityIncrement
         *   2.否则,扩容后的长度为 oldCapacity * 2
         */
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        
        //判断按照上面的计算后是否满足当前所需要的长度,不满足的话进入if语句
        if (newCapacity - minCapacity <= 0) {
            //溢出 直接抛错
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();
            //没有溢出,直接将当前所需要的长度返回
            return minCapacity;
        }
        
        /*
         * MAX_ARRAY_SIZE = INF - 8
         * 这里去判断newCapacity是否溢出或者newCapacity大于MAX_ARRAY_SIZE
         * 并且没有溢出,此时直接分配INF。
         *   这里的处理ArrayList相同,参考
         * [https://blog.csdn.net/qq_46312987/article/details/122096262]
         */
        return (newCapacity - MAX_ARRAY_SIZE <= 0)
            ? newCapacity
            : hugeCapacity(minCapacity);
    }

//              ||    
//  		    ||
// 				\/

    private static int hugeCapacity(int minCapacity) {
        //溢出 直接抛OOM
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        
        return (minCapacity > MAX_ARRAY_SIZE) ?
            //minCapacity > MAX_ARRAY_SIZE 并且没有溢出(上面if判断),直接分配INF
            Integer.MAX_VALUE :
        	//否则分配MAX_ARRAY_SIZE
            MAX_ARRAY_SIZE;
    }

3.3remove()

    /*
     *  (同步方法) 将指定索引位置的元素置为NULL
     */
	public synchronized E remove(int index) {
        modCount++;
        //越界判断
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);
        //获取index位置的元素
        E oldValue = elementData(index);
		
        //这里计算出当前准备删除的元素后有多少个元素
        int numMoved = elementCount - index - 1;
        
        //调用System.arraycopy变向的将index位置后面的所有元素往前移动一位
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        //将最后一个位置置为NULL。
        elementData[--elementCount] = null; // Let gc do its work
		
        //返回旧的value。
        return oldValue;
    }


//              ||    
//  		    ||
// 				\/
	
	/*
	 * 获取指定索引位置的元素
	 */
    E elementData(int index) {
        return (E) elementData[index];
    }

3.4set()

    /*
     * (同步方法) 修改指定索引位置的元素
     */
	public synchronized E set(int index, E element) {
        //判断索引是否越界
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);
		//获取index位置的元素
        E oldValue = elementData(index);
        //替换
        elementData[index] = element;
        //返回原元素
        return oldValue;
    }

3.5size()/isEmpty()

    //返回elementCount
	public synchronized int size() {
        return elementCount;
    }
	
	//判断elementCount是否为0
    public synchronized boolean isEmpty() {
        return elementCount == 0;
    }

3.6get()

   /*
    * 同步方法 获取指定索引位置的元素
    */
	public synchronized E get(int index) {
		// 索引越界判断
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);
		//直接返回index位置的元素。
        return elementData(index);
    }

//              ||    
//  		    ||
// 				\/
	
	/*
	 * 获取指定索引位置的元素
	 */
    E elementData(int index) {
        return (E) elementData[index];
    }

4.总结

  • Vector是非懒加载的,调用无参构造器时默认会初始化一个长度为10的数组。

  • 默认的扩容为原长度的2倍(ArrayList为1.5倍)(未给capacityIncrement赋值时)。

  • Vector的方法基本都是加了synchronized的,是一个线程安全的容器。

由于Vector现在基本不用,所以这里只讲解了其核心的方法,下期我们简单分析一下Vector的子类-Stack的源码。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shstart7

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值