成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

集合源碼學(xué)習(xí)之路---ArrayList

neroneroffy / 948人閱讀

摘要:雖然迭代器不常用,但是里面的一些知識(shí)點(diǎn),設(shè)計(jì)模式我們還是要學(xué)習(xí)以下的。需要注意的是,在使用迭代器期間,若使用非迭代器對(duì)容器進(jìn)行數(shù)據(jù)結(jié)構(gòu)上的改變,將會(huì)通過(guò)報(bào)錯(cuò)。

ArrayList簡(jiǎn)單介紹

ArrayList底層數(shù)據(jù)結(jié)構(gòu)使用的是數(shù)組,也就是線性表的順序存儲(chǔ)結(jié)構(gòu),是一段連續(xù)的存儲(chǔ)單元。具有存取快,增刪慢的特點(diǎn)。ArrayList不是線程安全的

類(lèi)定義

從類(lèi)定義上看,arrayList是支持泛型的,繼承自AbstractList,實(shí)現(xiàn)了List接口。同時(shí)實(shí)現(xiàn)了Serializable接口,因?yàn)樗С中蛄谢?,支持序列化傳輸。?shí)現(xiàn)了Cloneable接口,可以被克隆。實(shí)現(xiàn)了RandomAccess接口,可以被快速訪問(wèn),實(shí)際上就是通過(guò)下標(biāo)進(jìn)行訪問(wèn),RandomAccess只是一個(gè)標(biāo)記,無(wú)任何定義。

public class ArrayList extends AbstractList
        implements List, RandomAccess, Cloneable, java.io.Serializable
類(lèi)屬性
private static final long serialVersionUID = 8683452581122892189L;
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData;
private int size;

serialVersionUID:是實(shí)現(xiàn)了Serializable可自動(dòng)生成的。簡(jiǎn)單來(lái)說(shuō),Java的序列化機(jī)制是通過(guò)在運(yùn)行時(shí)判斷類(lèi)的serialVersionUID來(lái)驗(yàn)證版本一致性的。在進(jìn)行反序列化時(shí),JVM會(huì)把傳來(lái)的字節(jié)流中的serialVersionUID與本地相應(yīng)實(shí)體(類(lèi))的serialVersionUID進(jìn)行比較,如果相同就認(rèn)為是一致的,可以進(jìn)行反序列化,否則就會(huì)出現(xiàn)序列化版本不一致的異常。

EMPTY_ELEMENTDATA & DEFAULTCAPACITY_EMPTY_ELEMENTDATA :其實(shí)兩個(gè)都是一個(gè)空數(shù)組,只不過(guò)再明確長(zhǎng)度為0時(shí),會(huì)用EMPTY_ELEMENTDATA,無(wú)參構(gòu)造調(diào)用會(huì)用DEFAULTCAPACITY_EMPTY_ELEMENTDATA.

DEFAULT_CAPACITY:當(dāng)沒(méi)有指定容量,第一次添加元素,arraylist的初始容量.

elementData:arraylist的buffer,arrayList的容量就是elementData的容量。當(dāng)arraylist為空時(shí),elementData就是DEFAULTCAPACITY_EMPTY_ELEMENTDATA,當(dāng)添加第一個(gè)元素的時(shí)候,會(huì)自動(dòng)擴(kuò)容DEFAULT_CAPACITY(10)長(zhǎng)度.注意到,它被transient修飾,也就是不參與序列化,只存在調(diào)用者的內(nèi)存當(dāng)中。

size:arraylist含有元素的個(gè)數(shù)。

構(gòu)造函數(shù)
public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
public ArrayList(Collection c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

arraylist一共定義了三個(gè)構(gòu)造函數(shù)。

構(gòu)造一個(gè)指定大小的elementData

初始化一個(gè)默認(rèn)數(shù)組DEFAULTCAPACITY_EMPTY_ELEMENTDATA

將一個(gè)集合Collection初始化為arrayList

核心方法
/**
trim就是去除兩段空格的意思,這個(gè)方法是用來(lái)給elementdata瘦身用,將占據(jù)的多余的空間給釋放掉
*/
public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }
/**
確保容器容量,若為空,minCapacity去當(dāng)前值和默認(rèn)容量的最大值,然后判斷是否進(jìn)行擴(kuò)容
*/
private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }
/**
minCapacity大于數(shù)組長(zhǎng)度,則調(diào)用grow函數(shù)進(jìn)行擴(kuò)容
*/
private void ensureExplicitCapacity(int minCapacity) {
        /**
        modCount:是父類(lèi)AbstractList的變量。集合中所有用到modCount的都是線程不安全的。在做對(duì)線性表結(jié)構(gòu)修改的操作會(huì)對(duì)modCount進(jìn)行+1,當(dāng)我們調(diào)用iterator,會(huì)檢測(cè)modCount是不是我們期望的,如果在調(diào)用期間modCount又發(fā)生了變化,iterator將拋出異常.
        */
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
/**
獲取到數(shù)組長(zhǎng)度,對(duì)其進(jìn)行擴(kuò)容,增加將近一半的容量,使用Arrays.copyOF進(jìn)行擴(kuò)容
*/
private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
//返回容器元素個(gè)數(shù)
public int size() {
        return size;
    }
//判斷是否為空
public boolean isEmpty() {
        return size == 0;
    }
/**
兩個(gè)方法都是判斷索引正否越界
*/
private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    /**
     * A version of rangeCheck used by add and addAll.
     */
    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
/**
* 此方法用戶(hù)往線性表最后一位插入元素,若容器容量足夠,則時(shí)間復(fù)雜度是O(1),若需要擴(kuò)容,則時(shí)間復(fù)雜度是O(n)
*/
public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
/**
* 此方法用于向指定位置插入元素,時(shí)間復(fù)雜度為O(n)
*    1.判斷角標(biāo)是否越界  2.保證數(shù)組容量足夠,不夠通過(guò)新建數(shù)組擴(kuò)容 3.從數(shù)組指定索引復(fù)制直到最后一位,全*部加一
*/
public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }
//刪除制定索引元素,需算出位移量,將index之后的其他元素提前一位,其復(fù)雜度為o(n)
public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }
    //遍及elementData,若值相同,則調(diào)用fastRemove移除
    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
    //此方法和remove大致相同,只是少了判斷索引越界的問(wèn)題,因?yàn)樵诒徽{(diào)用前已經(jīng)通過(guò)遍歷方式驗(yàn)證了
    private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work
    }
迭代器

什么是迭代器呢?其實(shí)就是用來(lái)遍歷容器內(nèi)部分或全部元素的對(duì)象,每個(gè)迭代器代表容器中確定的地址,我們把具有類(lèi)似行為的都叫迭代器。雖然迭代器不常用,但是里面的一些知識(shí)點(diǎn),設(shè)計(jì)模式我們還是要學(xué)習(xí)以下的。arraylist迭代器分為Iterator和ListIterator。Iterator接口只定義了遍歷和刪除的職責(zé),ListIterator繼承于Iterator,新增了add和set方法,方便我們?cè)诘臅r(shí)候增加刪除元素。需要注意的是,在使用迭代器期間,若使用非迭代器對(duì)容器進(jìn)行數(shù)據(jù)結(jié)構(gòu)上的改變,將會(huì)通過(guò)checkForComodification()報(bào)錯(cuò)。

ListIterator的實(shí)現(xiàn)如下:

private class ListItr extends Itr implements ListIterator {
        ListItr(int index) {
            super();
            cursor = index;
        }

        public boolean hasPrevious() {
            return cursor != 0;
        }

        public int nextIndex() {
            return cursor;
        }

        public int previousIndex() {
            return cursor - 1;
        }

        @SuppressWarnings("unchecked")
        public E previous() {
            checkForComodification();
            int i = cursor - 1;
            if (i < 0)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i;
            return (E) elementData[lastRet = i];
        }

        public void set(E e) {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.set(lastRet, e);
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        public void add(E e) {
            checkForComodification();

            try {
                int i = cursor;
                ArrayList.this.add(i, e);
                cursor = i + 1;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    }
總結(jié)

arraylist源碼方法實(shí)在是過(guò)多,無(wú)法一一向大家解釋?zhuān)贿^(guò)相信大家理解上面的,再去研究剩下的內(nèi)容應(yīng)該沒(méi)有多大問(wèn)題。通過(guò)學(xué)習(xí)源碼,我們可以更清楚的知道arraylist在操作時(shí),底層結(jié)構(gòu)發(fā)生了哪些變化,為什么arraylist適合存取,不適合增刪.

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/68029.html

相關(guān)文章

  • 集合源碼學(xué)習(xí)之路---linkedlist

    摘要:類(lèi)定義是接口的簡(jiǎn)化版,支持按次序訪問(wèn),支持隨機(jī)訪問(wèn)。否則將原尾節(jié)點(diǎn)的尾指針指向。在某結(jié)點(diǎn)之前插入元素。根據(jù)索引隨機(jī)訪問(wèn),為方法的真正實(shí)現(xiàn)。總結(jié)其實(shí)只要你對(duì)雙向鏈表結(jié)構(gòu)比較熟悉,那源碼讀起來(lái)就會(huì)很輕松。 linkedlist簡(jiǎn)單介紹(jdk1.8) linkedlist的底層結(jié)構(gòu)是線性表的雙向鏈表,每個(gè)節(jié)點(diǎn)包括兩個(gè)指針域(一個(gè)指向前驅(qū)結(jié)點(diǎn),一個(gè)指向后繼結(jié)點(diǎn))和一個(gè)數(shù)據(jù)域,因?yàn)殡p指針域的獨(dú)...

    stackfing 評(píng)論0 收藏0
  • JAVA學(xué)習(xí)之路 (十)集合

    摘要:集合中的集合是一種工具類(lèi),就像是容器,存儲(chǔ)任意數(shù)量的具有共同屬性的對(duì)象集合的作用在類(lèi)的內(nèi)部,對(duì)數(shù)據(jù)進(jìn)行組織簡(jiǎn)單而快速的搜索大量數(shù)目的條目有的集合接口,提供了一系列排列有序的元素,并且可以在序列中進(jìn)行快速的插入和刪除有些集合接口,提供了映射關(guān) 集合 java中的集合: 是一種工具類(lèi),就像是容器,存儲(chǔ)任意數(shù)量的具有共同屬性的對(duì)象 集合的作用 1. 在類(lèi)的內(nèi)部,對(duì)數(shù)據(jù)進(jìn)行組織 2. 簡(jiǎn)單而快...

    sutaking 評(píng)論0 收藏0
  • 我的阿里之路+Java面經(jīng)考點(diǎn)

    摘要:我的是忙碌的一年,從年初備戰(zhàn)實(shí)習(xí)春招,年三十都在死磕源碼,三月份經(jīng)歷了阿里五次面試,四月順利收到實(shí)習(xí)。因?yàn)槲倚睦砗芮宄?,我的目?biāo)是阿里。所以在收到阿里之后的那晚,我重新規(guī)劃了接下來(lái)的學(xué)習(xí)計(jì)劃,將我的短期目標(biāo)更新成拿下阿里轉(zhuǎn)正。 我的2017是忙碌的一年,從年初備戰(zhàn)實(shí)習(xí)春招,年三十都在死磕JDK源碼,三月份經(jīng)歷了阿里五次面試,四月順利收到實(shí)習(xí)offer。然后五月懷著忐忑的心情開(kāi)始了螞蟻金...

    姘擱『 評(píng)論0 收藏0
  • [學(xué)習(xí)筆記-Java集合-1] List - ArrayList源碼分析

    摘要:源碼分析默認(rèn)容量默認(rèn)容量為,也就是通過(guò)創(chuàng)建時(shí)的默認(rèn)容量。集合中元素的個(gè)數(shù)真正存儲(chǔ)元素的個(gè)數(shù),而不是數(shù)組的長(zhǎng)度。方法刪除指定元素值的元素,時(shí)間復(fù)雜度為。方法求兩個(gè)集合的交集。 簡(jiǎn)介 ArrayList是一種以數(shù)組實(shí)現(xiàn)的List,與數(shù)組相比,它具有動(dòng)態(tài)擴(kuò)展的能力,因此也可稱(chēng)之為動(dòng)態(tài)數(shù)組。 繼承體系 showImg(https://segmentfault.com/img/bVbv8Ow?w...

    wind5o 評(píng)論0 收藏0
  • Java 常用List集合使用場(chǎng)景分析

    摘要:常用集合使用場(chǎng)景分析過(guò)年前的最后一篇,本章通過(guò)介紹,,,底層實(shí)現(xiàn)原理和四個(gè)集合的區(qū)別。和都是線程安全的,不同的是前者使用類(lèi),后者使用關(guān)鍵字。面試官會(huì)認(rèn)為你是一個(gè)基礎(chǔ)扎實(shí),內(nèi)功深厚的人才到這里常用集合使用場(chǎng)景分析就結(jié)束了。 Java 常用List集合使用場(chǎng)景分析 過(guò)年前的最后一篇,本章通過(guò)介紹ArrayList,LinkedList,Vector,CopyOnWriteArrayList...

    godruoyi 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<