Vector源码阅读(jdk11)
1.概述
- 和ArrayList一样,都是用Object[] elementdata数组来维护元素的内容,功能和用法和ArrayList一致;
- ArraysList是线程不安全的,而Vector是线程安全的,关键方法用了synchronized关键字上锁,保证了线程的安全,但是效率有所降低;
- 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并没有超过数组最大值,则新的容量为数组最大值
}
到此,扩容过成就全部讲完了,好像也没有太复杂。接下来再简述一下构造和扩容的过程:
构造过程:
- 如果调用无参构造,则默认初始容量为10,增幅为0,扩容时直接2倍;
- 如果构造器中只有一个参数,则初始容量为就是这个参数,增幅为0;
- 如果构造器中有两个参数,则前者为容量,后者为增幅;
- 如果构造器中是一个集合,则会将集合转化为数组后存放,容量相一致。
扩容过程:
- 首先调用ensure确保函数,判断minCapacity值是否有效(大于0才有效,否则不需要保证);
- 然后是helper帮助器,判断原来的容量是否确实容不下minCapacity个元素;如果能容下,什么都不做;
- 如果不能容下,调用grow()方法;然后如果指定了增幅,那就加上增幅,反之就扩容为2倍;然后判断扩容之后是否可以装下minCapacity个元素,如果还是不能装下,那就直接让容量等于minCapacity;然后判断此时的容量有没有超过数组最大值;如果没有超过,就可以进行数组拷贝了,完成。
- 如果超过了数组最大值,就需要去判断,到底是不是真的需要这么大的容量,也就是说,如果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初学爱好者,共同学习,欢迎指正,大佬轻喷。