Vector源码解析

Vector源码解析

继承接口

  • 继承了 AbstractList 类,这个类也实现了 List 方法
  • 实现了 Serializable ,能进行序列化操作
  • 实现了 Cloneable 接口,能够使用 clone() 方法
  • 实现了RandomAccess,说明 Vector 也支持随机访问,在 Vector 中,可以通过元素的索引快速获取元素对象,这就是快速随机访问。

在这里插入图片描述

成员变量

	// 存储数据的数组,此数组的容量一般大于实际长度,后续未填充数据用 null 替代
	protected Object[] elementData;
    // 实际元素个数
    protected int elementCount;

    // 容量增量,当容量不足以容纳元素时,自动扩容的大小。如果此值<=0 则扩容一倍
    protected int capacityIncrement;
	// 最大容量
	private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

构造函数

	// 构造一个空数组,默认容量10,容量增量为0。
	public Vector() {
        this(10);
    }

	// 指定初始容量,容量增量为0
	public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }
	

	//指定初始容量,指定容量增量
	public Vector(int initialCapacity, int capacityIncrement) {
        // 调 AbstractList 的无参构造
        super();
        // 初始容量 < 0 抛出异常
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+  initialCapacity);
        
        // 初始化elementData,容量为指定的
        this.elementData = new Object[initialCapacity];
        // 设置容量增量
        this.capacityIncrement = capacityIncrement;
    }
	
	//用指定集合初始化数组
	public Vector(Collection<? extends E> c) {
        //将c转换为Object数组
        elementData = c.toArray();
        //容量个数赋值
        elementCount = elementData.length;
        // c.toArray();可能返回的不是object数组,如果不是用copy方法再拷贝一次
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
    }

核心方法

trimToSize()

将底层数组的容量调整为当前vector实际元素的个数,来释放空间。

 public synchronized void trimToSize() {
        //修改次数+1
        modCount++;
        //记录旧容量
        int oldCapacity = elementData.length;
        //如果实际元素个数<容量
        if (elementCount < oldCapacity) {
            //将数组长度修剪为实际元素个数,调用native方法拷贝
            elementData = Arrays.copyOf(elementData, elementCount);
        }
    }
add过程分析

add(E e): 将指定的元素附加到此 Vector 的尾部

 public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }

ensureCapacityHelper(int minCapacity):

判断元素个数是否越界,调用扩容函数

private void ensureCapacityHelper(int minCapacity) {
        // 判断当前元素个数+1是否大于数组长度,大于则扩容
        if (minCapacity - elementData.length > 0)
            //传入元素个数
            grow(minCapacity);
    }

grow(int minCapacity)

扩容函数

private void grow(int minCapacity) {
        //保存旧容量
        int oldCapacity = elementData.length;
        //扩容:新容量=旧容量+旧容量(当容量增量为0或者负数时)
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        //如果新容量还小于传入容量
        if (newCapacity - minCapacity < 0)
            //将扩容后的容量再次扩容为想要的最小容量
            newCapacity = minCapacity;
        //如果扩容后的容量大于临界值(integer的最大值-8),则进行大容量分配
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            //返回integer最大值或者最大值-8
            newCapacity = hugeCapacity(minCapacity);
        //拷贝新数组到Vector
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    /**
     * 进行大容量分配
     */
    private static int hugeCapacity(int minCapacity) {
        //如果minCapacity<0,抛出异常
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        //如果想要的容量大于MAX_ARRAY_SIZE,则分配Integer.MAX_VALUE,否则分配MAX_ARRAY_SIZE
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

get和set
	 public synchronized E get(int index) {     
        //判断下标是否越界
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);
        //调用elementData(下标)返回对应元素
        return elementData(index);
    }
    
   public synchronized E set(int index, E element) {
        //判断下标是否越界
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);
        //oldValue保存返回数组对应下标的元素
        E oldValue = elementData(index);
        //对应位置赋值
        elementData[index] = element;
        //返回旧值
        return oldValue;
    }

	//直接返回数组对应下标的元素
    E elementData(int index) {
        return (E) elementData[index];
    }

remove(Object o)
	public boolean remove(Object o) {
        return removeElement(o);
    }
	// 删除元素后会把被删除元素后面的所有元素向左移动一个位置
	public synchronized boolean removeElement(Object obj) {
        // modCount + 1
        modCount++;
        // 找到第一个出现此元素的下标
        int i = indexOf(obj);
        if (i >= 0) {
            // 如果元素存在则删除
            removeElementAt(i);
            return true;
        }
        return false;
    }

	public int indexOf(Object o) {
        // 从下标 0 开始找
        return indexOf(o, 0);
    }

	// 返回下标
	public synchronized int indexOf(Object o, int index) {
        //如果传入对象为空
        if (o == null) {
            //遍历数组,找数组中为空的元素
            for (int i = index ; i < elementCount ; i++)
                if (elementData[i]==null)
                    //找到了返回下标
                    return i;
        } else {
            //不为空
            for (int i = index ; i < elementCount ; i++)
                //找相等的元素
                if (o.equals(elementData[i]))
                    //返回下标
                    return i;
        }
        //没找到返回-
        return -1;
    }

	public synchronized void removeElementAt(int index) {
        // modCount + 1
        modCount++;
        // 数组下标是否越界
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " +
                                                     elementCount);
        } else if (index < 0) {
            throw new ArrayIndexOutOfBoundsException(index);
        }
        //计算要移动的元素个数
        int j = elementCount - index - 1;
        if (j > 0) {
            // 如果删除的不是最后一个需要移动元素
            System.arraycopy(elementData, index + 1, elementData, index, j);
        }
        // 数量 - 1
        elementCount--;
        // 最后一个元素设置为 null 
        elementData[elementCount] = null; /* to let gc do its work */
    }

remove(int)
public synchronized E remove(int index) {
        //改动次数+1
        modCount++;
        //下标越界
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);
        //保存旧值
        E oldValue = elementData(index);
        
        //计算要移动元素的个数
        int numMoved = elementCount - index - 1;
        //如果移动数>0 ,拷贝
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        //末尾元素设为空,让gc回收
        elementData[--elementCount] = null; // Let gc do its work
        //返回旧值
        return oldValue;
    }

Vector 和ArrayList 的区别

  • Vector的方法都是同步的(Synchronized),线程安全,而ArrayList的方法不是,由于线程的同步必然要影响性能,因此,ArrayList的性能比Vector好
  • 当Vector或ArrayList中的元素超过它的初始大小时**,Vector会将它的容量翻倍(未设置容量增量时),而ArrayList扩容为1.5倍**,这样,ArrayList就有利于节约内存空间

List集合对比

List接口一共有三个实现类,分别是ArrayList、Vector和LinkedLis

  1. ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素进行快速随机访问。数组的缺点是每个元素之间不能有间隔,当数组大小不满足时需要增加存储能力,就要讲已经有数组的数据复制到新的存储空间中。当在ArrayList的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除
  2. VectorArrayList一样,也是通过数组实现的,不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢
  3. LinkedList是用链表结构存储数据的,很适合数据的动态插入和删除,但是随机访问遍历速度比较慢。另外,他还提供了List接口中没有定义的方法,可以直接操作表头表尾元素,可以当作堆栈、队列和双向队列使用
  4. vector线程同步Synchronized)的,所以它也是线程安全的,而Arraylist是线程异步(ASynchronized)的,是不安全的。如果不考虑线程的安全因素,一般用Arraylist效率比较高
  5. 如果集合中的元素的数目大于目前集合数组的长度时,vector增长率为目前数组长度的100%,而arraylist增长率为目前数组长度的50%.如过在集合中使用数据量比较大的数据,用vector比较好

元素操作

如果查找一个指定位置的数据,vectorarraylist使用的时间是相同的,都是0(1),这个时候使用vectorarraylist都可以,Linkedlist而查询一个指定位置的数据时花费的时间为0(i)

如果移动一个指定位置的数据vectorarraylist花费的时间为0(n-i),这时候应该使用Linkedlist,因为它移动一个指定位置的数据所花费的时间为0(1)

原因:

ArrayListVector是采用数组方式存储数据,允许直接通过索引定位元素,但是插入数据要涉及到数组元素移动 等内存操作,所以查找数据快插入数据慢Vector由于使用了synchronized方法所以性能上比ArrayList要差,LinkedList使用双向链表实现存储,可以根据索引在整个链表中的位置进行向前或向后遍历,但是插入数据时只需要操作被删除结点的前后结点即可,所以插入速度较快

时间复杂度查找一个指定位置移动一个指定位置的数据
vector0(1)0(n-i)
arraylist0(1)0(n-i)
Linkedlist0(i)0(1)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值