Java集合類源碼解析:Vector

来源:https://www.cnblogs.com/yeya/archive/2018/11/19/9970654.html
-Advertisement-
Play Games

引言 之前的文章我們學習了一個集合類 "ArrayList" ,今天講它的一個兄弟 Vector 。 為什麼說是它兄弟呢?因為從容器的構造來說,Vector 簡直就是 ArrayList 的翻版,也是基於數組的數據結構,不同的是,Vector的每個方法都加了 synchronized 修飾符,是線程 ...


引言

之前的文章我們學習了一個集合類 ArrayList,今天講它的一個兄弟 Vector
為什麼說是它兄弟呢?因為從容器的構造來說,Vector 簡直就是 ArrayList 的翻版,也是基於數組的數據結構,不同的是,Vector的每個方法都加了 synchronized 修飾符,是線程安全的。

類聲明

用idea打開 Vector 的源碼,不難發現,它的類聲明跟 ArrayList 一模一樣,都是繼承了AbstractList,並且都實現了RandomAccess 介面,遍歷元素用for迴圈的效率要優於迭代器。

 * @author  Lee Boynton
 * @author  Jonathan Payne
 * @see Collection
 * @see LinkedList
 * @since   JDK1.0
 */
public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable

值得說明的是,從註釋上來看,Vector 是 JDK1.0版本就引進的,屬於最古老的集合類的那一批,而ArrayList是 1.2才引進的,所以說,Vector才是哥哥,ArrayList是小弟,哈哈~~~~

基本變數和構造函數

基本變數

Vector 的基本變數有四個,分別是:

  • 底層數組
protected Object[] elementData;
  • 數組元素個數
protected int elementCount;
  • 增長的容量大小,如果這個值小於或等於0,擴容時會擴大 2 倍,
capacityIncrement
  • 最大容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

構造函數

//創建初識容量為10的數組,增長量0
public Vector() {
    this(10);
}
//創建初識容量可變的數組,增長量為0
public Vector(int initialCapacity) {
    this(initialCapacity, 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;
}
//創建一個包含指定集合的數組
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);
 }

看的出來,Vector的構造器和成員變數和ArrayList大同小異。

成員方法

擴容

Vector 與 ArrayList 雖然很類似,但在擴容大小這方面還是有區別的,ArrayList 預設擴容後的大小為原容量 的1.5倍,而Vector則是先判斷增長量大小,如果是非正數,那就擴大為原來的2倍,看一下它的擴容方法:

//參數是最小需要的容量
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    //如果增長量不大於0,擴容為2倍大小
    //一般預設創建的容器都是不傳增長量的,所以預設增長量是0,也就是預設直接擴容兩倍
    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;
    }

添加

Vector的添加方法都是加上 synchronized關鍵字的,並且添加前檢測容量,判斷是否擴容:

//加入元素到數組結尾,同步的
public synchronized boolean add(E e) {
    modCount++;
    //檢測容量
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = e;
    return true;
} 
//檢測容量大小,超過數組長度就做擴容
private void ensureCapacityHelper(int minCapacity) {
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
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);
        }
        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 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;
    }

Vector的添加方法代碼不是很複雜,跟ArrayList 一樣,本質上都是對數組做插入數據的操作,不同的是,方法都加了synchronized 修飾,所以,它的添加方法都是線程安全的。

其他操作元素的方法也是這樣的套路,這裡不打算一一列舉了,因為都跟ArrayList 差不多,另外,Vector 比 ArrayList 多了一個迭代方法

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");
        }
    };
}

返回的是一個Enumeration 介面對象,大概也是個容器介面,沒用過,不說太多。

Vector 對比 ArrayList

最後,總結一下 Vector 和 ArrayList 的對比吧。

相同點:

  • 底層都是基於數組的結構,預設容量都是10;

  • 都實現了RandomAccess 介面,支持隨機訪問;

  • 都有擴容機制;

區別:

  • Vector 的方法有做同步操作,是屬於線程安全的,而ArrayList 是非線程安全的;

  • Vector預設情況下擴容後的大小為原來的2倍,而ArrayList 是1.5倍;

  • Vector 比 ArrayList 多了一種迭代器 Enumeration;

雖然Vector相較ArrayList做了同步的處理,但這樣也影響了效率,因為每次調用方法都要獲取鎖,所以,一般情況下,對集合的線程安全沒有需求的話,推薦使用 ArrayList。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前端工程師,也叫Web前端開發工程師。web前端,前端從字面意思就很好理解,前端就是負責網站框架,首頁內容的設計。web前端是IT行業門檻相對較低的類別,很容易學洗。經過幾個月的培訓一般就可以上崗就業。 Web前端開發技術主要包括三個要素:HTML、CSS和JavaScript! 它要求前端開發工程 ...
  • 我估計有很多像我這樣非電腦專業的人進入到前端之後,總是在寫業務代碼,思考什麼什麼效果如何實現,導致很多基礎概念型的東西都理解得並不太清楚。經常一碰到群里討論的些筆試題什麼的,總覺得自己像是一個假前端似的,似懂非懂,就算會做也不能清楚的表述為什麼會是那樣的結果。總是自己安慰自己,反正正常項目很少這麼 ...
  • 1.父界面向子界面傳值 [1].父界面打開子界面: [2].子界面接收父界面的值 2.子界面向父界面傳值 [1].子界面向父界面傳值 [2].父界面接收子界面的值 ...
  • mock.js的文檔真的是無力吐槽,只說明API怎麼使用,完全不說明mock.js這個工具怎麼用,最有意思的是google的大部分文章複製官網的API, 不管是react還是Vue都是下麵的流程 本文主要記錄mock這個工具怎麼使用,api自己看 "文檔" 1. 安裝mock.js 1. 在項目裡面 ...
  • 朋友們,起風了,該“浪”起來了。 今天帶大家“浪”的主題是js的數組去重,總結了幾種方法如下,希望有所幫助,希望同行之間的交流,更希望有大神批評指點!!! 方法1:利用ES6的Set結合Array.from去重 方法二:利用ES5中的Index.Of()方法 方法三:利用數組中filter方法 方法 ...
  • 英文名:Singleton Pattern。英文原話:Ensure a class has only one instance,and provide a global point of access to it。 單例模式的主要作用是確保一個類只有一個實例。 一、實現方式 1.靜態內部類 這是最好 ...
  • 從大學到現在,這本書也許我反反覆復地讀了不下十遍,可是這次終於有了勇氣把他標註為看過,因為直到今天我才自信自己真的理解了裡面所講的架構模式。 對於現在的互聯網時代,所有的開發思想都是強調簡潔,強調“敏捷”,甚至曾經流行一時的OOD竟然有被嫌棄的趨勢 《企業應用架構模式》作者是當今面向對象軟體開發的權 ...
  • 在互聯網產品運營中,有很多小伙伴或許會遇到這樣的困擾:產品好不容易推出來了,流量成本節節攀升,用戶的活躍度、留存度卻持續下降。因此在瞬息萬變的互聯網產品環境中,需要研發接入支付系統來加入商業行為的閉環,支付系統能夠幫助企業更好地實現商業化,利用那些為用戶而生的支付體系產品,實現用戶積累、商業變現。對... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...