吃透Java集合系列五:Vector和Stack

文章首發(fā)csdn博客地址:https://blog.csdn.net/u013277209?viewmode=contents

一:Vector分析

Vector 是線程安全的動態(tài)數(shù)組串述,同 ArrayList 一樣繼承自 AbstractList 且實現(xiàn)了 List执解、RandomAccess、Cloneable纲酗、Serializable 接口衰腌。
內(nèi)部實現(xiàn)依然基于數(shù)組,Vector 與 ArrayList 基本是一致的觅赊,唯一不同的是 Vector 是線程安全的右蕊,會在可能出現(xiàn)線程安全的方法前面加上 synchronized 關(guān)鍵字。
其和 ArrayList 類似吮螺,隨機訪問速度快饶囚,插入和移除性能較差(數(shù)組原因),支持 null 元素鸠补,有順序萝风,元素可以重復(fù),線程安全紫岩。

變量以及初始化:

    /**
     * 存儲元素數(shù)組
     */
    protected Object[] elementData;

    /**
     * 元素個數(shù)
     */
    protected int elementCount;

    /**
     * 容量增長的系數(shù)
     */
    protected int capacityIncrement;

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -2767605614048989439L;

    /**
     * 指定容量和增長系數(shù)的構(gòu)造函數(shù)
     */
    public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }

    /**
     * 指定容量構(gòu)造函數(shù)
     */
    public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }

    /**
     * 空構(gòu)造函數(shù)闹丐,默認容量10
     */
    public Vector() {
        this(10);
    }

    /**
     * 包含指定集合的構(gòu)造函數(shù)
     */
    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);
    }

elementData前面并沒有transient關(guān)鍵字,但是他也實現(xiàn)了自定義序列化操作被因,前面我們了解過卿拴,如果類中自定義了readObject和writeObject,那么序列化時會調(diào)用這兩個函數(shù)梨与,如果類中不自定義readObject與writeObject堕花,那么類在序列化的時候會調(diào)用ObjectInputStream與ObjectOutputStream中的defaultReadObject與defaultWriteObject方法進行默認序列化。
下面我們看一下Vector中自定義的readObject和writeObject

private void readObject(ObjectInputStream in)
            throws IOException, ClassNotFoundException {
        ObjectInputStream.GetField gfields = in.readFields();
        int count = gfields.get("elementCount", 0);
        Object[] data = (Object[])gfields.get("elementData", null);
        if (count < 0 || data == null || count > data.length) {
            throw new StreamCorruptedException("Inconsistent vector internals");
        }
        elementCount = count;
        elementData = data.clone();
    }

    private void writeObject(java.io.ObjectOutputStream s)
            throws java.io.IOException {
        final java.io.ObjectOutputStream.PutField fields = s.putFields();
        final Object[] data;
        synchronized (this) {
            fields.put("capacityIncrement", capacityIncrement);
            fields.put("elementCount", elementCount);
            data = elementData.clone();
        }
        fields.put("elementData", data);
        s.writeFields();
    }

擴容
Vector 在 capacityIncrement 大于 0 時擴容 capacityIncrement 大小粥鞋,否則擴容為原始容量的 2 倍缘挽,而ArrayList 在默認數(shù)組容量不夠時默認擴展是 1.5 倍。

    public synchronized void ensureCapacity(int minCapacity) {
        if (minCapacity > 0) {
            modCount++;
            ensureCapacityHelper(minCapacity);
        }
    }
    private void ensureCapacityHelper(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        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是JDK1.0時已經(jīng)有的呻粹,而List框架是1.2時才出現(xiàn)的壕曼,所以Vector在List接口定義的增刪改查以外還有他自己定義的增刪改查方法,我們來看一下:

    public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }
    public synchronized void addElement(E obj) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = obj;
    }


    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 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 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--;
        elementData[elementCount] = null; /* to let gc do its work */
    }
    
    
    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 E get(int index) {
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);

        return elementData(index);
    }
    public synchronized E elementAt(int index) {
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
        }

        return elementData(index);
    }

增刪改查方法基本上一樣等浊,所以Vector里面包含了大量實現(xiàn)相同的方法腮郊。

迭代器實現(xiàn)
Vector中迭代器實現(xiàn)和ArrayList中一樣的,只不過Vector中為了保證線程安全筹燕,在方法體里面加了synchronized關(guān)鍵字轧飞。

    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() {
            // Racy but within spec, since modifications are checked
            // within or after synchronization in next/previous
            return cursor != elementCount;
        }

        public E next() {
            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();
            synchronized (Vector.this) {
                checkForComodification();
                Vector.this.remove(lastRet);
                expectedModCount = modCount;
            }
            cursor = lastRet;
            lastRet = -1;
        }

        @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();
        }
    }

    /**
     * An optimized version of AbstractList.ListItr
     */
    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;
        }
    }

克隆實現(xiàn)
Vector克隆實現(xiàn)和ArrayList的實現(xiàn)一致,都是通過數(shù)組元素拷貝來實現(xiàn)的淺拷貝

public synchronized Object clone() {
        try {
            @SuppressWarnings("unchecked")
                Vector<E> v = (Vector<E>) super.clone();
            v.elementData = Arrays.copyOf(elementData, elementCount);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }

為什么現(xiàn)在都不提倡使用 Vector 了撒踪?

因為 Vector 實現(xiàn)并發(fā)安全的原理是在每個操作方法上加鎖过咬,這些鎖并不是必須要的,在實際開發(fā)中一般都是通過鎖一系列的操作來實現(xiàn)線程安全制妄,也就是說將需要同步的資源放一起加鎖來保證線程安全掸绞,如果多個 Thread 并發(fā)執(zhí)行一個已經(jīng)加鎖的方法,但是在該方法中又有 Vector 的存在耕捞,Vector 本身實現(xiàn)中已經(jīng)加鎖了衔掸,雙重鎖會造成額外的開銷,即 Vector 同 ArrayList 一樣有 fail-fast 問題(即無法保證遍歷安全)砸脊,所以在遍歷 Vector 操作時又得額外加鎖保證安全具篇,還不如直接用 ArrayList 加鎖性能好,所以在 JDK 1.5 之后推薦使用 java.util.concurrent 包下的并發(fā)類凌埂。此外 Vector 是一個從 JDK1.0 就有的古老集合驱显,那時候 Java 還沒有提供系統(tǒng)的集合框架,所以在 Vector 里提供了一些方法名很長的方法(如 addElement(Object obj)瞳抓,實際上這個方法和 add(Object obj) 沒什么區(qū)別)埃疫,從 JDK1.2 以后 Java 提供了集合框架,然后就將 Vector 改為實現(xiàn) List 接口孩哑,從而導(dǎo)致 Vector 里有一些重復(fù)的方法栓霜。

二、Stack分析

通過繼承Vector類横蜒,Stack類可以很容易的實現(xiàn)他本身的功能胳蛮。因為大部分的功能在Vector里面已經(jīng)提供支持了销凑。
在Java中Stack類表示后進先出(LIFO)的對象堆棧。棧是一種非常常見的數(shù)據(jù)結(jié)構(gòu)仅炊,它采用典型的先進后出的操作方式完成的斗幼。
Stack通過五個操作對Vector進行擴展,允許將向量視為堆棧抚垄。這個五個操作如下:

  1. empty() 測試堆棧是否為空蜕窿。
  2. peek() 查看堆棧頂部的對象,但不從堆棧中移除它呆馁。
  3. pop() 移除堆棧頂部的對象桐经,并作為此函數(shù)的值返回該對象。
  4. push(E item) 把項壓入堆棧頂部浙滤。
  5. search(Object o) 返回對象在堆棧中的位置阴挣,以 1 為基數(shù)。

我們看一下源碼:


public class Stack<E> extends Vector<E> {
    /**
     * Creates an empty Stack.
     */
    public Stack() {
    }

    /**
     * 將元素存入棧頂
     */
    public E push(E item) {
        addElement(item);

        return item;
    }

    /**
     * 返回棧頂元素瓷叫,并將其從棧中刪除
     */
    public synchronized E pop() {
        E       obj;
        int     len = size();

        obj = peek();
        removeElementAt(len - 1);

        return obj;
    }

    /**
     * 返回棧頂元素节猿,不執(zhí)行刪除操作
     */
    public synchronized E peek() {
        int     len = size();

        if (len == 0)
            throw new EmptyStackException();
        return elementAt(len - 1);
    }

    /**
     * 棧是否為空
     */
    public boolean empty() {
        return size() == 0;
    }

    /**
     * 查找“元素o”在棧中的位置:由棧底向棧頂方向數(shù)
     */
    public synchronized int search(Object o) {
        int i = lastIndexOf(o);

        if (i >= 0) {
            return size() - i;
        }
        return -1;
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末碌冶,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌痒留,老刑警劉巖佩憾,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挚币,死亡現(xiàn)場離奇詭異艾凯,居然都是意外死亡,警方通過查閱死者的電腦和手機煮寡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門虹蓄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人幸撕,你說我怎么就攤上這事薇组。” “怎么了坐儿?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵律胀,是天一觀的道長。 經(jīng)常有香客問我貌矿,道長炭菌,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任逛漫,我火速辦了婚禮黑低,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘酌毡。我一直安慰自己克握,他們只是感情好蕾管,可當(dāng)我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著菩暗,像睡著了一般娇掏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上勋眯,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天,我揣著相機與錄音下梢,去河邊找鬼客蹋。 笑死,一個胖子當(dāng)著我的面吹牛孽江,可吹牛的內(nèi)容都是我干的讶坯。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼岗屏,長吁一口氣:“原來是場噩夢啊……” “哼辆琅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起这刷,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤婉烟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后暇屋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體似袁,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年咐刨,在試婚紗的時候發(fā)現(xiàn)自己被綠了昙衅。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡定鸟,死狀恐怖而涉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情联予,我是刑警寧澤啼县,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站躯泰,受9級特大地震影響谭羔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜麦向,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一瘟裸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧诵竭,春花似錦话告、人聲如沸兼搏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽佛呻。三九已至,卻和暖如春病线,著一層夾襖步出監(jiān)牢的瞬間吓著,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工送挑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留绑莺,地道東北人。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓惕耕,卻偏偏與公主長得像纺裁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子司澎,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 先是忘記放鹽欺缘,后來鹽又放多了。 豬肉的比雞肉的好吃挤安。 憧憬了好幾天谚殊,真做出來,吃幾個就吃不下了漱受。
    阿彌陀佛加油鴨閱讀 171評論 2 0
  • 那一望無際的戈壁灘上 懸著幾樹電網(wǎng) 沒有茵茵綠草 只有一片連一片的黃丘 還有幾只搭窩的鴉 那天上來的黃河 帶著滾滾...
    橘子俠閱讀 359評論 0 0
  • 知道嗎络凿,之前無論我怎樣放肆,怎樣取鬧昂羡,我都是肆無忌憚絮记。因為我覺得無論如何你不會離開我,有你相伴虐先,你會寵著我怨愤。可是后...
    醉夢醒浮生閱讀 323評論 0 0
  • 常用命令 想看看你的Shell是哪一種蛹批,執(zhí)行命令: echo $SHELL在Linux中撰洗,$符號代表一個shell...
    蒲公英少年閱讀 3,618評論 1 16