前言
上一次分析集合的源码还是4.20,一晃半个月过去了,由于hashMap中遇到了红黑树,于是我决定去看下二叉排序树,AVL,B,B+,RB-Tree,这几种树,然后这10几天中因为《深入理解JVM》到了,也基本上都在看,看到了200页。后悔当时数据结构没好好学,AVL之流都没咋学。不过放下负担,好好去学才是正解,下面进入正题Vector
开篇疑问
在我看过的资料中,或者博文中,都会简单的说,ArrayList和Vector的区别在于ArrayList是1.5倍扩容Vector是2倍扩容,还有就是线程安全,今天看了源码的我,才发现,原来Vectory还可以支持定量增容
维护的属性
维护的属性很简单,主要有三个
protected Object[] elementData; //储存对象的数组
protected int elementCount; // 对象的计数
protected int capacityIncrement; // 指定的增量大小
构造方法
1、无参数构造,默认容量为10,不提供增量大小->0
public Vector() {
this(10);
}
2、提供初始容量,不提供增量大小->0
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
3、提供初始容量和增量大小,检测增量值要大于0
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
构造方法通过逐级调用,从而达到默认值的效果
add增加
public synchronized boolean add(E e) {
modCount++;
add(e, elementData, elementCount);
return true;
}
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
elementCount = s + 1;
}
我们可以看到,当容量满了的时候就会进行扩容操作grow,扩容是比较有意思的地方
扩容
// 将旧容量+1,作为参数传递
private Object[] grow() {
return grow(elementCount + 1);
}
//数组复制,查看一下newCapacity( )
private Object[] grow(int minCapacity) {
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity <= 0) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return minCapacity;
}
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}
真正的扩容就是newCapacity()这个函数,首先它判断增量是否大于0,也就是判断是否有最初设定的增量大小,如果有增量大小,新容量=增量+旧容量,如果没有增量则容量变为原来的两倍,同时确保容量不超过最大容量MAX__ARRAY__SIZE
删除remove
public boolean remove(Object o) {
return removeElement(o);
}
public synchronized boolean removeElement(Object obj) {
modCount++;
int i = indexOf(obj);
if (i >= 0) {
removeElementAt(i);
return true;
}
return false;
}
// 找到对象的索引
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) {
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);
}
modCount++;
elementCount--;
elementData[elementCount] = null; /* to let gc do its work */
}
需要看一下这个复制的API
void java.lang.System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
它的意思是,从原数组的某一个位置开始复制到新数组的某一个元素,总长度是length,它是由Hotspot虚拟机来实现的。同样ArrayList中,也是用这种方法是实现的,叫fastRemove()
遍历
package test;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;
public class Test
{
public static void main(String[] args)
{
Vector<String> vector = new Vector();
vector.add("1");
vector.add("2");
vector.add("3");
// index访问
for (int i = 0; i < vector.size(); i++) {
System.out.println(vector.get(i));
}
// for循环
for (String string : vector) {
System.out.println(string);
}
//迭代器
Iterator<String> it = vector.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
// Enumeration
Enumeration<String> enumeration = vector.elements();
while (enumeration.hasMoreElements()) {
System.out.println(enumeration.nextElement());
}
}
}
之前我只知道iterator迭代器,今天才发现原来还有枚举,查看这个接口的定义
Enumeration
public interface Enumeration<E> {
boolean hasMoreElements();
E nextElement();
default Iterator<E> asIterator() {
return new Iterator<>() {
@Override public boolean hasNext() {
return hasMoreElements();
}
@Override public E next() {
return nextElement();
}
};
}
这个接口主要是访问,并不提供删除操作,但是也可以通过它来返回一个iterator迭代器,也就是asIterator方法
总结
总的来说,它的重点在于扩容提供的增量扩容,可以提供固定的增长量,然后还有一个就是认识了下Enumberation这个接口,它的内部实现还是不难的,所以到这里就算是了解了