Vector源码阅读

Vector源码阅读(jdk11)

1.概述

  1. 和ArrayList一样,都是用Object[] elementdata数组来维护元素的内容,功能和用法和ArrayList一致;
  2. ArraysList是线程不安全的,而Vector是线程安全的,关键方法用了synchronized关键字上锁,保证了线程的安全,但是效率有所降低;
  3. ArrayList和Vector的扩容机制稍显不同。

2.构造方法

先来看看vector中有那些重要的属性

protected Object[] elementData;//存放元素的数组
protected int elementCount;//数组中元素的个数
protected int capacityIncrement;//每次扩容的增福,如果没有设定,会自动初始化为0
private static final long serialVersionUID = -2767605614048989439L;//
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//常量

构造方法怎么样

/**
*在构造时传入初始容量和增幅,前者初始化数组,而后者等待扩容时调用
*/
public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }
/**
*在构造时传入初始容量,然后调用第一个构造方法默认增幅为0
*/
public Vector(int initialCapacity) {
    this(initialCapacity, 0);
}
/**
*在构造时什么都不传入,则会默认初始容量为10,并且增幅0
*/
public Vector() {
    this(10);
}
/**
*在构造时传入一个集合,默认容量为这个集合的大小,而增幅这里却没有说
*/
public Vector(Collection<? extends E> c) {
    Object[] a = c.toArray();
    elementCount = a.length;
    if (c.getClass() == ArrayList.class) {//没有写错,源代码如是也
        elementData = a;
    } else {
        elementData = Arrays.copyOf(a, elementCount, Object[].class);
    }
}

3.扩容过程

扩容的过程会涉及多个函数,有些许复杂。

首先映入眼帘的,是一个保证至少存minCapacity个元素的函数:

public synchronized void ensureCapacity(int minCapacity) {//保证可以存minCapacity个元素
    if (minCapacity > 0) {
        modCount++;//对vector的修改次数
        ensureCapacityHelper(minCapacity);//调用确认帮助器,主要目的应该是解耦
    }
}

然后就是确认帮助器:

private void ensureCapacityHelper(int minCapacity) {//保证可以存
    if (minCapacity - elementData.length > 0)//如果确实存不下这么多个元素
        grow(minCapacity);//进行扩容,否则啥也不干
}

然后就是真正的扩容函数:grow()

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//常量,至于为什么是这么大我也  不知道
private void grow(int minCapacity) {
    int oldCapacity = elementData.length;//初始容量
    
    //这里判断增幅是否被设置,如果没有就变为两倍,如果有就按增幅增
    int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                     capacityIncrement : oldCapacity);
    
    //判断扩容之后是否达到了要求的最小值minCapacity,如果没有,那么直接把容量设置为该minCapacity
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    
    //如果新的容量已经超出了规定的数组最大值,那么直接进入huge找到最节省空间的大小
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);
}

huge()函数:

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?//判断要求的minCapacity是否超过数组最大值
        Integer.MAX_VALUE ://如果这是真的,那么就取Integer最大值
        MAX_ARRAY_SIZE;//如果minCapacity并没有超过数组最大值,则新的容量为数组最大值
}

到此,扩容过成就全部讲完了,好像也没有太复杂。接下来再简述一下构造和扩容的过程:

构造过程:

  1. 如果调用无参构造,则默认初始容量为10,增幅为0,扩容时直接2倍;
  2. 如果构造器中只有一个参数,则初始容量为就是这个参数,增幅为0;
  3. 如果构造器中有两个参数,则前者为容量,后者为增幅;
  4. 如果构造器中是一个集合,则会将集合转化为数组后存放,容量相一致。

扩容过程:

  1. 首先调用ensure确保函数,判断minCapacity值是否有效(大于0才有效,否则不需要保证);
  2. 然后是helper帮助器,判断原来的容量是否确实容不下minCapacity个元素;如果能容下,什么都不做;
  3. 如果不能容下,调用grow()方法;然后如果指定了增幅,那就加上增幅,反之就扩容为2倍;然后判断扩容之后是否可以装下minCapacity个元素,如果还是不能装下,那就直接让容量等于minCapacity;然后判断此时的容量有没有超过数组最大值;如果没有超过,就可以进行数组拷贝了,完成。
  4. 如果超过了数组最大值,就需要去判断,到底是不是真的需要这么大的容量,也就是说,如果minCapacity没有超过数组最大值,那就让容量等于数组最大值,如果确实超过了数组最大值,就让容量等于Integer最大值。最后数组拷贝,历经千辛万苦,终于完成扩容。

4.一些常用的方法

1.add方法:

没搞懂意义何在。。。感觉没必要多加一个addElement()方法。

public synchronized void addElement(E obj) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = obj;
}
public synchronized boolean add(E e) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = e;
    return true;
}
public void add(int index, E element) {
    insertElementAt(element, index);
}
public synchronized boolean addAll(Collection<? extends E> c) {
    modCount++;
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityHelper(elementCount + numNew);
    System.arraycopy(a, 0, elementData, elementCount, numNew);
    elementCount += numNew;
    return numNew != 0;
}

2.remove方法:

这个就更迷惑了,真的有必要吗

public synchronized boolean removeElement(Object obj) {
    modCount++;
    int i = indexOf(obj);
    if (i >= 0) {
        removeElementAt(i);
        return true;
    }
    return false;
}
public boolean remove(Object o) {
    return removeElement(o);
}
public synchronized E remove(int index) {
    modCount++;
    if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index);
    E oldValue = elementData(index);

    int numMoved = elementCount - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--elementCount] = null; // Let gc do its work

    return oldValue;
}
public synchronized boolean removeAll(Collection<?> c) {
    return super.removeAll(c);
}

3.set和get方法:

public synchronized E get(int index) {
    if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index);

    return elementData(index);
}
public synchronized E set(int index, E element) {
    if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index);

    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}

5.结束语

java初学爱好者,共同学习,欢迎指正,大佬轻喷。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值