Java中的Vector詳細(xì)解讀
一、Vector介紹
Vector是實(shí)現(xiàn)了List接口的子類,其底層是一個(gè)對(duì)象數(shù)組,維護(hù)了一個(gè)elementData數(shù)組,是線程安全的,Vector類的方法帶有synchronized關(guān)鍵字,在開(kāi)發(fā)中考慮線程安全中使用Vector。
二、源碼解析
1、Vector實(shí)現(xiàn)的接口
如下圖所示:

觀察上圖,發(fā)現(xiàn)Vector繼承了AbstractList<E>,并實(shí)現(xiàn)了三個(gè)接口,分別是:Serializable、Cloneable和RandomAccess。下面對(duì)Vector中繼承的類和實(shí)現(xiàn)的接口進(jìn)行簡(jiǎn)單的介紹:
- AbstractList類:該類實(shí)現(xiàn)了List接口里面的方法,并且為其提供了默認(rèn)代碼實(shí)現(xiàn)。而List接口中主要定義了集合常用的方法讓ArrayList進(jìn)行實(shí)現(xiàn),如:add、addAll、contains、remove、size、indexOf等方法。
- Serializable接口:主要用于序列化,即:能夠?qū)?duì)象寫入磁盤。與之對(duì)應(yīng)的還有反序列化操作,就是將對(duì)象從磁盤中讀取出來(lái)。因此如果要進(jìn)行序列化和反序列化,ArrayList的實(shí)例對(duì)象就必須實(shí)現(xiàn)這個(gè)接口,否則在實(shí)例化的時(shí)候程序會(huì)報(bào)錯(cuò)(java.io.NotSerializableException)。
- Cloneable接口:實(shí)現(xiàn)Cloneable接口的類能夠調(diào)用clone方法,如果沒(méi)有實(shí)現(xiàn)Cloneable接口就調(diào)用方法,就會(huì)拋出異常(java.lang.CloneNotSupportedException)。
- RandomAccess接口:該接口表示可以隨機(jī)訪問(wèn)ArrayList當(dāng)中的數(shù)據(jù)。隨機(jī)訪問(wèn)是指我們可以在常量時(shí)間復(fù)雜度內(nèi)進(jìn)行數(shù)據(jù)的方法,因?yàn)锳rrayList的底層實(shí)現(xiàn)是數(shù)組,而數(shù)組是可以隨機(jī)訪問(wèn)的。
2、Vector的構(gòu)造方法
(1)無(wú)參構(gòu)造方法
public Vector() {
this(10);
}總結(jié):Vector的無(wú)參構(gòu)造方法中會(huì)調(diào)用有參構(gòu)造方法,創(chuàng)建一個(gè)內(nèi)部數(shù)組,該內(nèi)部數(shù)組的初始容量為10,增量為0
(2)帶初始容量的構(gòu)造方法
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}總結(jié):構(gòu)造一個(gè)內(nèi)部數(shù)組,該數(shù)組的容量為指定的容量,增量為0。
(3)帶初始容量和增量的構(gòu)造方法
public Vector(int initialCapacity, int capacityIncrement) {
super();
//如果初始容量小于0,拋出異常
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
//指定容量
this.elementData = new Object[initialCapacity];
//指定增量
this.capacityIncrement = capacityIncrement;
}總結(jié):構(gòu)造一個(gè)具有初始容量和增量的數(shù)組。
(4)集合型構(gòu)造方法
public Vector(Collection<? extends E> c) {
elementData = c.toArray();
elementCount = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}總結(jié):構(gòu)造指定集合元素的數(shù)組。
3、Vector中的變量
Vector底層也是數(shù)組實(shí)現(xiàn)的,其主要變量有:
- elementData::Vector是基于數(shù)組的一個(gè)實(shí)現(xiàn),elementData就是底層的數(shù)組
- elementCount:數(shù)組元素個(gè)數(shù)
- capacityIncrement:指定Vector容量不足的擴(kuò)容量,不指定的情況下默認(rèn)翻倍
4、Vector主要方法解析
(1)add方法解析
從上面對(duì)于Vector構(gòu)造方法的分析,不難發(fā)現(xiàn)Vector和ArrayList的默認(rèn)初始容量都是10。那么,我們看看Vector的add()方法又是如何實(shí)現(xiàn)的?
public synchronized boolean add(E e) {
//AbstractList中的變量
modCount++;
//確保數(shù)組容量是否足夠
ensureCapacityHelper(elementCount + 1);
//把元素添加到數(shù)組中
elementData[elementCount++] = e;
return true;
}可以看到:add方法添加一個(gè)元素到列表的末尾。它首先通過(guò)ensureCapacityHelper(elemetnCount+1)來(lái)保證Object[]數(shù)組有足夠的空間存放添加的數(shù)據(jù),然后再將添加的數(shù)據(jù)存放到數(shù)組對(duì)應(yīng)位置上。
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}通過(guò)ensureCapacityHelper()方法判斷最小容量和當(dāng)前數(shù)組長(zhǎng)度,若所需的最小容量大于數(shù)組大小,則需要進(jìn)行擴(kuò)容,然后調(diào)用grow()方法實(shí)現(xiàn)擴(kuò)容。
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
//舊數(shù)組的長(zhǎng)度
int oldCapacity = elementData.length;
//如果指定了增量,則新數(shù)組長(zhǎng)度=舊數(shù)組長(zhǎng)度+增量;如果沒(méi)有指定容量,則新數(shù)組長(zhǎng)度=舊數(shù)組長(zhǎng)度2倍
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
//判斷新容量減去最小容量是否小于0,如果是第一次調(diào)用add,則必然小于
if (newCapacity - minCapacity < 0)
//將最小容量賦給新容量
newCapacity = minCapacity;
/判斷新容量減去最大數(shù)組大小是否大于0,如果時(shí)則計(jì)算出一個(gè)超大容量
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
//調(diào)用數(shù)組工具類方法,創(chuàng)建一個(gè)新數(shù)組,將新數(shù)組的地址賦值給elementData
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
//如果最小容量小于0,拋出異常;否則就比較并返回
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}Step1:先將當(dāng)前數(shù)組大小賦值給oldCapacity,然后判斷是否有指定增量的值,如果有,則新數(shù)組長(zhǎng)度=舊數(shù)組長(zhǎng)度+增量;如果沒(méi)有,則新數(shù)組長(zhǎng)度=舊數(shù)組長(zhǎng)度*2。
Step2:利用newCapacity進(jìn)行兩次判斷:
第一次判斷 if (newCapacity - minCapacity < 0),判斷擴(kuò)容后容量是否大于minCapacity,若小于minCapacity,則直接將minCapacity賦值給newCapacity第二次判斷 if (newCapacity - MAX_ARRAY_SIZE > 0),判斷newCapacity 是否超出了ArrayList所定義的最大容量,若超出了,則調(diào)用hugeCapacity()來(lái)比較minCapacity和 MAX_ARRAY_SIZE, 如果minCapacity大于MAX_ARRAY_SIZE,則新容量則為 Interger.MAX_VALUE,否則,新容量大小則為 MAX_ARRAY_SIZE。
Step3:最終得到newCapacity,然后調(diào)用Arrays.copyOf()方法進(jìn)行擴(kuò)容
綜合上述分析,有以下幾個(gè)點(diǎn):
- Vector如果不指定初始容量,則默認(rèn)創(chuàng)建一個(gè)長(zhǎng)度為10的數(shù)組。
- Vector如果不指定初始增量,則擴(kuò)容機(jī)制為:新數(shù)組長(zhǎng)度=舊數(shù)組長(zhǎng)度*2;如果指定初始增量,則擴(kuò)容機(jī)制為:新數(shù)組長(zhǎng)度=舊數(shù)組長(zhǎng)度+增量。
- Vector的add()方法是加了synchronized關(guān)鍵字的,這就意味著它是線程安全的。
接下來(lái)可以看看如何在指定位置添加元素:
//在指定位置添加元素
public void add(int index, E element) {
insertElementAt(element, index);
}
//添加元素到指定位置
public synchronized void insertElementAt(E obj, int index) {
modCount++;
//檢查位置合法性
if (index > elementCount) {
throw new ArrayIndexOutOfBoundsException(index
+ " > " + elementCount);
}
//判斷是否需要擴(kuò)容
ensureCapacityHelper(elementCount + 1);
//拷貝數(shù)組
System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
//添加元素
elementData[index] = obj;
elementCount++;
}可以看到:在指定位置添加元素,首先進(jìn)行了數(shù)組范圍的檢查,防止越界,然后調(diào)用方法檢驗(yàn)是否要擴(kuò)容,且增量++,之后完成數(shù)組拷貝即可。
(2)remove()方法
public boolean remove(Object o) {
return removeElement(o);
}
public synchronized boolean removeElement(Object obj) {
modCount++;
//獲取該元素所在的數(shù)組下標(biāo)
int i = indexOf(obj);
//如果該元素存在,則移除元素
if (i >= 0) {
removeElementAt(i);
return true;
}
return false;
}
public synchronized void removeElementAt(int index) {
modCount++;
//如果下標(biāo)越界,拋出異常
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " +
elementCount);
}
else if (index < 0) { //下標(biāo)小于0,拋出異常
throw new ArrayIndexOutOfBoundsException(index);
}
//刪除元素
int j = elementCount - index - 1;
if (j > 0) {
System.arraycopy(elementData, index + 1, elementData, index, j);
}
elementCount--;
elementData[elementCount] = null; /* to let gc do its work */
}由上述分析:刪除元素同樣需要進(jìn)行范圍校驗(yàn)。然后計(jì)算刪除需要移動(dòng)的數(shù)據(jù),再通過(guò)數(shù)組拷貝移動(dòng)數(shù)組。其次還有一個(gè)小細(xì)節(jié),可以發(fā)現(xiàn)remove()方法是有返回值的,而這個(gè)返回值就是我們刪除的元素的值。同樣的,真正移除元素的remove()方法也是加鎖了的。
(3)set()方法
該方法加了synchronized關(guān)鍵字保證安全性,用來(lái)設(shè)置指定下標(biāo)的數(shù)據(jù),進(jìn)行元素?cái)?shù)據(jù)的更新。
public synchronized E set(int index, E element) {
//判斷合法性
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
//修改舊值
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}(4) get()方法
該方法用來(lái)獲取對(duì)應(yīng)下標(biāo)的數(shù)據(jù),也是加鎖的方法。
public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}(5)其他方法
Vector中的其他方法,如:判斷是否為空、獲取長(zhǎng)度等方法,都是加了鎖的。因此,可以認(rèn)為Vector是線程安全的。


關(guān)于Vector中的迭代器,這里不再贅述,有興趣的可以看這篇文章,里面對(duì)Itr進(jìn)行了介紹:深入理解ArrayList
三、總結(jié)
1、Vector簡(jiǎn)單總結(jié)
- Vector的底層實(shí)現(xiàn)也是數(shù)組,在不指定初始容量的情況下,默認(rèn)初始數(shù)組大小為10,其擴(kuò)容機(jī)制為:當(dāng)指定了增量的時(shí)候,新擴(kuò)容的容量=舊數(shù)組長(zhǎng)度+容量;如果沒(méi)有指定增量,新擴(kuò)容容量=舊數(shù)組長(zhǎng)度*2。
- Vector是線程安全的,因?yàn)樗鼘?duì)很多方法都加鎖了。
- Vector和ArrayList都是數(shù)組實(shí)現(xiàn)的,因此其支持快速隨機(jī)訪問(wèn),但增加元素和刪除元素的操作卻是比較耗時(shí)的。
2、對(duì)比ArrayList
相同:兩個(gè)類都實(shí)現(xiàn)了List接口,它們都是有序且元素可重復(fù)的集合。
不同:
(1)ArrayList 是線程不安全的,Vector 是線程安全的。ArrayList 是線程不安全的,所以當(dāng)我們不需要保證線程安全性的時(shí)候推薦使用 ArrayList,如果想要在多線程中使用 ArrayList 可以通過(guò) Collections.synchronizedList(new ArrayList()) 或 new CopyOnWriteArrayList 的方式創(chuàng)建一個(gè)線程安全的 ArrayList 集合;Vector 類的所有方法都是同步的??梢杂袃蓚€(gè)線程安全的訪問(wèn)一個(gè) Vector 對(duì)象,但是一個(gè)線程訪問(wèn) Vector 的話會(huì)在同步操作上耗費(fèi)大量的時(shí)間。
(2)ArrayList 使用默認(rèn)構(gòu)造器創(chuàng)建對(duì)象時(shí)是在調(diào)用 add() 方法時(shí)對(duì) ArrayList 的默認(rèn)容量進(jìn)行初始化的,Vector 在調(diào)用構(gòu)造器時(shí)就對(duì)容量進(jìn)行了初始化
(3)ArrayList 存儲(chǔ)數(shù)據(jù)的 Object 數(shù)組使用了transient關(guān)鍵字,Vector 的 Object 數(shù)組沒(méi)有。
關(guān)于transient關(guān)鍵字的說(shuō)明:如果用 transient 聲明一個(gè)實(shí)例變量,當(dāng)對(duì)象存儲(chǔ)時(shí),它的值不需要維持。這里的對(duì)象存儲(chǔ)是指,Java 的 serialization 提供的一種持久化對(duì)象實(shí)例的機(jī)制。當(dāng)一個(gè)對(duì)象被序列化的時(shí)候,transient型變量的值不包括在序列化的表示中,然而非transient型的變量是被包括進(jìn)去的。例如:當(dāng)持久化對(duì)象時(shí),可能有一個(gè)特殊的對(duì)象數(shù)據(jù)成員,我們不想用 serialization 機(jī)制來(lái)保存它。為了在一個(gè)特定對(duì)象的一個(gè)域上關(guān)閉 serialization,可以在這個(gè)域前加上關(guān)鍵字 transient。
簡(jiǎn)單的說(shuō),就是被 transient 修飾的成員變量,在序列化的時(shí)候其值會(huì)被忽略,在被反序列化后, transient 變量的值被設(shè)為初始值, 如 int 型的是 0,對(duì)象型的是 null 。
(4)擴(kuò)容機(jī)制不同。ArrayList擴(kuò)容機(jī)制為變?yōu)樵瓉?lái)的1.5倍,而Vector擴(kuò)容時(shí)如果指定了增量,則新數(shù)組長(zhǎng)度=舊數(shù)組長(zhǎng)度+增量,如果沒(méi)有指定,就擴(kuò)容為原來(lái)的2倍。
到此這篇關(guān)于Java中的Vector詳細(xì)解讀的文章就介紹到這了,更多相關(guān)Vector解讀內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot核心配置文件bootstrap與application用法
Spring Boot中有兩種配置文件:bootstrap和application,bootstrap是應(yīng)用程序的父上下文,優(yōu)先加載,不能被本地相同配置覆蓋,bootstrap主要用于加載外部配置信息,如SpringCloudConfig配置中心的配置,application主要用于Spring Boot項(xiàng)目的自動(dòng)化配置2024-12-12
Spring中的@Qualifier注解和@Resource注解區(qū)別解析
這篇文章主要介紹了Spring中的@Qualifier注解和@Resource注解區(qū)別解析,@Qualifier注解的用處是當(dāng)一個(gè)接口有多個(gè)實(shí)現(xiàn)的時(shí)候,為了指名具體調(diào)用哪個(gè)類的實(shí)現(xiàn),@Resource注解可以通過(guò) byName命名和byType類型的方式注入,需要的朋友可以參考下2023-11-11
SpringSecurity自定義資源攔截規(guī)則及登錄界面跳轉(zhuǎn)問(wèn)題
這篇文章主要介紹了SpringSecurity自定義資源攔截規(guī)則及登錄界面跳轉(zhuǎn)問(wèn)題,我們想要自定義認(rèn)證邏輯,就需要?jiǎng)?chuàng)建一些原來(lái)不存在的bean,這個(gè)時(shí)候就可以使@ConditionalOnMissingBean注解,本文給大家介紹的非常詳細(xì),需要的朋友參考下吧2023-12-12
spring聲明式事務(wù) @Transactional 不回滾的多種情況以及解決方案
本文主要介紹了spring聲明式事務(wù) @Transactional 不回滾的多種情況以及解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11
RocketMQ的push消費(fèi)方式實(shí)現(xiàn)示例
這篇文章主要為大家介紹了RocketMQ的push消費(fèi)方式實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪<BR>2022-08-08
關(guān)于Spring源碼深度解析(AOP功能源碼解析)
這篇文章主要介紹了關(guān)于Spring源碼深度解析(AOP功能源碼解析),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
Java多線程的原子性,可見(jiàn)性,有序性你都了解嗎
這篇文章主要為大家詳細(xì)介紹了Java多線程的原子性,可見(jiàn)性,有序性,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-03-03
java基于dom4j包實(shí)現(xiàn)對(duì)XML解析的方法
這篇文章主要介紹了java基于dom4j包實(shí)現(xiàn)對(duì)XML解析的方法,結(jié)合實(shí)例形式分析了java針對(duì)xml格式數(shù)據(jù)的相關(guān)解析操作實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-05-05

