Java 集合深入理解(12):古老的 Vector
點選檢視 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~
今天刮颱風,躲屋裡看看 Vector !
都說 Vector 是執行緒安全的 ArrayList,今天來根據原始碼看看是不是這麼相似。
什麼是 Vector
Vector 和 ArrayList 一樣,都是繼承自 AbstractList。它是 Stack 的父類。英文的意思是 “向量”。
Vector 成員變數
1.底層也是個陣列
protected Object[] elementData;
2.陣列元素個數,為啥不就叫 size 呢?奇怪
protected int elementCount;
3.擴容時增長數量,允許使用者自己設定。如果這個值是 0 或者 負數,擴容時會擴大 2 倍,而不是 1.5
protected int capacityIncrement;
4.預設容量
private static final int DEFAULT_SIZE = 10;
Vector 的 4 種構造方法
//建立預設容量 10 的陣列,同時增長量為 0
public Vector() {
this(DEFAULT_SIZE, 0);
}
//建立一個使用者指定容量的陣列,同時增長量為 0
public Vector(int capacity) {
this(capacity, 0);
}
//建立指定容量大小的陣列,設定增長量。如果增長量為 非正數,擴容時會擴大兩倍
public Vector(int capacity, int capacityIncrement) {
if (capacity < 0) {
throw new IllegalArgumentException("capacity < 0: " + capacity);
}
elementData = newElementArray(capacity);
elementCount = 0;
this.capacityIncrement = capacityIncrement;
}
//建立一個包含指定集合的陣列
public Vector(Collection<? extends E> c) {
//轉成陣列,賦值
elementData = c.toArray();
elementCount = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
//可能有這個神奇的 bug,用 Arrays.copyOf 重新建立、複製
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}
一個內部方法,返回一個新陣列:
private E[] newElementArray(int size) {
return (E[]) new Object[size];
}
Vector 的成員方法
1.先來看 JDK 7 中 Vector 的 3 種擴容方式:
//根據指定的容量進行擴容
private void grow(int newCapacity) {
//建立個指定容量的新陣列,這裡假設指定的容量比當前陣列元素個數多
E[] newData = newElementArray(newCapacity);
//把當前陣列複製到新建立的陣列
System.arraycopy(elementData, 0, newData, 0, elementCount);
//當前陣列指向新陣列
elementData = newData;
}
//預設增長一倍的擴容
private void growByOne() {
int adding = 0;
//擴容量 capacityIncrement 不大於 0,就增長一倍
if (capacityIncrement <= 0) {
if ((adding = elementData.length) == 0) {
adding = 1;
}
} else {
//否則按擴容量走
adding = capacityIncrement;
}
//建立個新陣列,大小為當前容量加上 adding
E[] newData = newElementArray(elementData.length + adding);
//複製,賦值
System.arraycopy(elementData, 0, newData, 0, elementCount);
elementData = newData;
}
//指定預設擴容數量的擴容
private void growBy(int required) {
int adding = 0;
//擴容量 capacityIncrement 不大於 0
if (capacityIncrement <= 0) {
//如果當前陣列內沒有元素,就按指定的數量擴容
if ((adding = elementData.length) == 0) {
adding = required;
}
//增加擴容數量到 指定的以上
while (adding < required) {
adding += adding;
}
} else {
//擴容量大於 0 ,還是按指定的擴容數量走啊
adding = (required / capacityIncrement) * capacityIncrement;
//不過也可能出現偏差,因為是 int 做除法,所以擴容值至少是 指定擴容量的一倍以上
if (adding < required) {
adding += capacityIncrement;
}
}
//建立,複製,賦值一條龍
E[] newData = newElementArray(elementData.length + adding);
System.arraycopy(elementData, 0, newData, 0, elementCount);
elementData = newData;
}
2.(我能說一開始看錯了,看成 JDK7 的了嗎 - -)再來看JDK 8 中的擴容機制,變成一種了:
//擴容,傳入最小容量,跟 ArrayList.grow(int) 很相似,只是擴大量不同
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
//如果增長量 capacityIncrement 不大於 0 ,就擴容 2 倍
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
//
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
3.Vector中的 5 種新增元素的方法
//擴容前兆,檢查數量
private void ensureCapacityHelper(int minCapacity) {
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//在指定位置插入一個元素,同步的
public synchronized void insertElementAt(E obj, int index) {
modCount++;
if (index > elementCount) {
throw new ArrayIndexOutOfBoundsException(index
+ " > " + elementCount);
}
ensureCapacityHelper(elementCount + 1);
//擴容後就把插入點後面的元素統一後移一位
System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
//賦值
elementData[index] = obj;
elementCount++;
}
//尾部插入元素,同步的
public synchronized void addElement(E obj) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = obj;
}
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;
}
//新增一個結合到指定位置,同步的
public synchronized boolean addAll(int index, Collection<? extends E> c) {
modCount++;
if (index < 0 || index > elementCount)
throw new ArrayIndexOutOfBoundsException(index);
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityHelper(elementCount + numNew);
//要移動多少個元素
int numMoved = elementCount - index;
if (numMoved > 0)
//把插入位置後面的元素後移這麼多位
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
//複製元素到陣列中
System.arraycopy(a, 0, elementData, index, numNew);
elementCount += numNew;
return numNew != 0;
}
最後還有個 ListIterator 的新增方法
public void add(E e) {
int i = cursor;
synchronized (Vector.this) {
checkForComodification();
Vector.this.add(i, e);
expectedModCount = modCount;
}
cursor = i + 1;
lastRet = -1;
}
4.Vector 中的 9 種刪除方法
//刪除指定位置的元素,同步的
public synchronized void removeElementAt(int index) {
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);
}
elementCount--;
//最後多餘的一位置為 null
elementData[elementCount] = null; /* to let gc do its work */
}
//刪除指定元素,同步的
public synchronized boolean removeElement(Object obj) {
modCount++;
int i = indexOf(obj);
if (i >= 0) {
removeElementAt(i);
return true;
}
return false;
}
E elementData(int index) {
return (E) elementData[index];
}
//刪除指定位置的元素
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);
//最後一位置為 null,不浪費空間
elementData[--elementCount] = null; // Let gc do its work
return oldValue;
}
public boolean remove(Object o) {
return removeElement(o);
}
//刪除指定集合的所有元素,同步的
public synchronized boolean removeAll(Collection<?> c) {
//直接呼叫 AbstractCollection 的 removeAll 方法,用迭代器挨個刪除
return super.removeAll(c);
}
//刪除所有元素,同步的
public synchronized void removeAllElements() {
modCount++;
// 挨個置為空,Let gc do its work
for (int i = 0; i < elementCount; i++)
elementData[i] = null;
elementCount = 0;
}
//刪除指定範圍的元素,同步的
protected synchronized void removeRange(int fromIndex, int toIndex) {
modCount++;
//把結束位置以後的元素向前移動 指定數量個位置,覆蓋
int numMoved = elementCount - toIndex;
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);
// 把多餘的位置置為 null
int newElementCount = elementCount - (toIndex-fromIndex);
while (elementCount != newElementCount)
elementData[--elementCount] = null;
}
//排除異己,同步的
public synchronized boolean retainAll(Collection<?> c) {
return super.retainAll(c);
}
//JDK 1.8 新增的
public synchronized boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
// 將要刪除的內容加入 removeSet
int removeCount = 0;
final int size = elementCount;
final BitSet removeSet = new BitSet(size);
final int expectedModCount = modCount;
for (int i=0; modCount == expectedModCount && i < size; i++) {
@SuppressWarnings("unchecked")
final E element = (E) elementData[i];
if (filter.test(element)) {
removeSet.set(i);
removeCount++;
}
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
// 遍歷,刪除
final boolean anyToRemove = removeCount > 0;
if (anyToRemove) {
final int newSize = size - removeCount;
for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
i = removeSet.nextClearBit(i);
elementData[j] = elementData[i];
}
for (int k=newSize; k < size; k++) {
elementData[k] = null; // Let gc do its work
}
elementCount = newSize;
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
return anyToRemove;
}
寫“同步的”寫的手抽筋,還是統計不是同步的方法吧 - -。
5. Vector 中的修改方法
//修改指定位置為指定元素
public synchronized E set(int index, E element) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
//找到這個元素,直接設定新值
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
//修改指定位置為指定元素
public synchronized void setElementAt(E obj, int index) {
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " +
elementCount);
}
//陣列就是方便,直接更新就好了
elementData[index] = obj;
}
//修改陣列容量
public synchronized void setSize(int newSize) {
modCount++;
//元素個數超出容量就要擴容
if (newSize > elementCount) {
ensureCapacityHelper(newSize);
} else {
//新增 elementCount - newSize 個元素
for (int i = newSize ; i < elementCount ; i++) {
elementData[i] = null;
}
}
elementCount = newSize;
}
//排序,修改順序
public synchronized void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
//用的是 Arrays.sort
Arrays.sort((E[]) elementData, 0, elementCount, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
//縮小陣列容量,減少佔用資源
public synchronized void trimToSize() {
modCount++;
int oldCapacity = elementData.length;
if (elementCount < oldCapacity) {
//新建個小點的陣列,賦值
elementData = Arrays.copyOf(elementData, elementCount);
}
}
6. Vector 中的查詢
//查詢 o 從指定位置 index 開始第一次出現的位置
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;
}
//查詢 o 在陣列中首次出現的位置
public int indexOf(Object o) {
return indexOf(o, 0);
}
//是否包含 O
public boolean contains(Object o) {
return indexOf(o, 0) >= 0;
}
//是否包含整個集合
public synchronized boolean containsAll(Collection<?> c) {
//呼叫 AbstractCollection 的方法,使用迭代器挨個遍歷查詢,兩重迴圈
return super.containsAll(c);
}
//第一個元素,其實提供了 get() 方法就夠了
public synchronized E firstElement() {
if (elementCount == 0) {
throw new NoSuchElementException();
}
return elementData(0);
}
//最後一個元素,其實提供了 get() 方法就夠了
public synchronized E lastElement() {
if (elementCount == 0) {
throw new NoSuchElementException();
}
return elementData(elementCount - 1);
}
public synchronized boolean isEmpty() {
return elementCount == 0;
}
//實際包含元素個數
public synchronized int size() {
return elementCount;
}
//陣列大小,>= 元素個數
public synchronized int capacity() {
return elementData.length;
}
7. Vector 也可以轉成陣列
public synchronized Object[] toArray() {
return Arrays.copyOf(elementData, elementCount);
}
//跟 ArrayList 簡直一樣
public synchronized <T> T[] toArray(T[] a) {
if (a.length < elementCount)
return (T[]) Arrays.copyOf(elementData, elementCount, a.getClass());
System.arraycopy(elementData, 0, a, 0, elementCount);
if (a.length > elementCount)
a[elementCount] = null;
return a;
}
8. Vector 中的迭代器
普通迭代器 Iterator:
public synchronized Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
// 呼叫 next() 前的檢查
return cursor != elementCount;
}
public E next() {
//注意了,Vector 連迭代器的方法也加了同步
synchronized (Vector.this) {
checkForComodification();
int i = cursor;
if (i >= elementCount)
throw new NoSuchElementException();
cursor = i + 1;
return elementData(lastRet = i);
}
}
public void remove() {
if (lastRet == -1)
throw new IllegalStateException();
//注意了,Vector 連迭代器的方法也加了同步
synchronized (Vector.this) {
checkForComodification();
Vector.this.remove(lastRet);
expectedModCount = modCount;
}
cursor = lastRet;
lastRet = -1;
}
//大概看下這個 1.8 的方法
@Override
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
synchronized (Vector.this) {
final int size = elementCount;
int i = cursor;
if (i >= size) {
return;
}
@SuppressWarnings("unchecked")
final E[] elementData = (E[]) Vector.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
action.accept(elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
ListIterator:
public synchronized ListIterator<E> listIterator(int index) {
if (index < 0 || index > elementCount)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}
final class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
super();
cursor = index;
}
public boolean hasPrevious() {
return cursor != 0;
}
public int nextIndex() {
return cursor;
}
public int previousIndex() {
return cursor - 1;
}
public E previous() {
synchronized (Vector.this) {
checkForComodification();
int i = cursor - 1;
if (i < 0)
throw new NoSuchElementException();
cursor = i;
return elementData(lastRet = i);
}
}
public void set(E e) {
if (lastRet == -1)
throw new IllegalStateException();
synchronized (Vector.this) {
checkForComodification();
Vector.this.set(lastRet, e);
}
}
public void add(E e) {
int i = cursor;
synchronized (Vector.this) {
checkForComodification();
Vector.this.add(i, e);
expectedModCount = modCount;
}
cursor = i + 1;
lastRet = -1;
}
}
//1.8 新增的略過。。。
//還多了個 sort 方法,自己傳入的集合需要實現比較器
@SuppressWarnings("unchecked")
@Override
public synchronized void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, elementCount, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
Vector 還支援 Enumeration 迭代:
public Enumeration<E> elements() {
return new Enumeration<E>() {
int count = 0;
public boolean hasMoreElements() {
return count < elementCount;
}
public E nextElement() {
synchronized (Vector.this) {
if (count < elementCount) {
return elementData(count++);
}
}
throw new NoSuchElementException("Vector Enumeration");
}
};
}
總結
Vector 特點
- 底層由一個可以增長的陣列組成
- Vector 通過 capacity (容量) 和 capacityIncrement (增長數量) 來儘量少的佔用空間
- 擴容時預設擴大兩倍
- 最好在插入大量元素前增加 vector 容量,那樣可以減少重新申請記憶體的次數
- 通過 iterator 和 lastIterator 獲得的迭代器是 fail-fast 的
- 通過 elements 獲得的老版迭代器 Enumeration 不是 fail-fast 的
- 同步類,每個方法前都有同步鎖 synchronized
- 在 JDK 2.0 以後,經過優化,Vector 也加入了 Java 集合框架大家族
Vector VS ArrayList
共同點:
- 都是基於陣列
- 都支援隨機訪問
- 預設容量都是 10
- 都有擴容機制
區別:
- Vector 出生的比較早,JDK 1.0 就出生了,ArrayList JDK 1.2 才出來
- Vector 比 ArrayList 多一種迭代器 Enumeration
- Vector 是執行緒安全的,ArrayList 不是
- Vector 預設擴容 2 倍,ArrayList 是 1.5
如果沒有執行緒安全的需求,一般推薦使用 ArrayList,而不是 Vector,因為每次都要獲取鎖,效率太低。
Thanks
https://docs.oracle.com/javase/8/docs/api/java/util/Vector.html
相關文章
- Java 集合系列:Vector原始碼深入解析Java原始碼
- Java集合——深入理解HashMapJavaHashMap
- 【java】【集合】List、ListIterator、VectorJava
- java集合【12】——— ArrayList,LinkedList,Vector的相同點與區別是什麼?Java
- 【Java】Java容器篇(二),深入理解List集合類Java
- Java List 常用集合 ArrayList、LinkedList、VectorJava
- Java集合的深度理解Java
- Java集合詳解(一):全面理解Java集合Java
- 萬字長文深入理解java中的集合-附PDF下載Java
- Java 集合系列2、百密一疏之VectorJava
- Java集合系列(二):ArrayList、LinkedList、Vector的使用方法及區別Java
- 深入理解Java中的AQSJavaAQS
- 深入理解Java中的鎖Java
- 深入理解 Java 中的 LambdaJava
- Java集合Stack原始碼深入解析Java原始碼
- Java 集合Hashtable原始碼深入解析Java原始碼
- java集合梳理【10】— Vector超級詳細原始碼分析Java原始碼
- 深入理解Java PriorityQueueJava
- 深入理解 Java 方法Java
- Java:IO:深入理解Java
- 深入理解Java反射Java反射
- 理解分析java集合操作之ConcurrentModificationExceptionJavaException
- 深入理解Java中的逃逸分析Java
- 深入理解Java中的鎖(二)Java
- 深入理解Java中的鎖(一)Java
- 深入理解Java中的Garbage CollectionJava
- 【JAVA】筆記(12)---集合(1)-概述篇Java筆記
- 【java】【集合】List的三個子類—ArrayList、Vector、LinkedList的區別和聯絡Java
- 深入理解 Java 泛型Java泛型
- 深入理解 Java 註解Java
- 深入理解Java異常Java
- 深入理解Java反射(一)Java反射
- 深入理解Java泛型Java泛型
- 深入理解 Java 列舉Java
- 深入理解 Java 陣列Java陣列
- 深入理解Java中的不可變物件Java物件
- 深入理解Java的分級引用模型Java模型
- 深入理解JVM(③)Java的鎖優化JVMJava優化
- 深入理解JVM(③)Java的模組化JVMJava