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

資訊專欄INFORMATION COLUMN

JDK1.8 ArrayList部分源碼分析小記

王軍 / 2985人閱讀

摘要:部分源碼分析小記底層數(shù)據(jù)結(jié)構(gòu)底層的數(shù)據(jù)結(jié)構(gòu)就是數(shù)組,數(shù)組元素類型為類型,即可以存放所有類型數(shù)據(jù)。初始容量大于初始化元素?cái)?shù)組新建一個(gè)數(shù)組初始容量為為空對象數(shù)組初始容量小于,拋出異常無參構(gòu)造函數(shù)。

JDK1.8 ArrayList部分源碼分析小記 底層數(shù)據(jù)結(jié)構(gòu)

底層的數(shù)據(jù)結(jié)構(gòu)就是數(shù)組,數(shù)組元素類型為Object類型,即可以存放所有類型數(shù)據(jù)。
我們對ArrayList類的實(shí)例的所有的操作底層都是基于數(shù)組的。

繼承與實(shí)現(xiàn)關(guān)系

ArrayList繼承的父類為:AbstractList(抽象類)
實(shí)現(xiàn)的接口有:List(規(guī)定了List的操作規(guī)范)、RandomAccess(可隨機(jī)訪問)、Cloneable(可拷貝)、Serializable(可序列化)

友情提示:因?yàn)锳rrayList實(shí)現(xiàn)了RandomAccess接口,所以盡量用for(int i = 0; i < size; i++) 來遍歷而不要用Iterator迭代器來遍歷,后者在效率上要差一些

public class ArrayList extends AbstractList
        implements List, RandomAccess, Cloneable, java.io.Serializable
部分屬性

類的屬性中核心的屬性為elementData,類型為Object[],用于存放實(shí)際元素,并且被標(biāo)記為transient,也就意味著在序列化的時(shí)候,此字段是不會被序列化的。

友情提示:ArrayList的默認(rèn)容量為10

    // 缺省容量
    private static final int DEFAULT_CAPACITY = 10;
    // 元素?cái)?shù)組(調(diào)用指定初始值的構(gòu)造函數(shù)時(shí)elementData的長度會變成指定值)
    transient Object[] elementData; 
    // 空對象數(shù)組
    private static final Object[] EMPTY_ELEMENTDATA = {};
    // 缺省空對象數(shù)組
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
常用構(gòu)造函數(shù)

友情提示:創(chuàng)建ArrayList時(shí)盡量設(shè)置初始大小(使用ArrayList(int initialCapacity)構(gòu)造函數(shù))

    /**
     * ArrayList帶容量大小的構(gòu)造函數(shù)
     *
     * @param initialCapacity
     */
    //說明:指定elementData數(shù)組的大小,不允許初始化大小小于0,否則拋出異常。
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {// 初始容量大于0
            this.elementData = new Object[initialCapacity];// 初始化元素?cái)?shù)組(新建一個(gè)數(shù)組)
        } else if (initialCapacity == 0) {// 初始容量為0
            this.elementData = EMPTY_ELEMENTDATA;// 為空對象數(shù)組
        } else {// 初始容量小于0,拋出異常
            throw new IllegalArgumentException("Illegal Capacity: " +
                    initialCapacity);
        }
    }
    
    /**
     * ArrayList無參構(gòu)造函數(shù)。默認(rèn)容量是10
     */
    //說明:當(dāng)未指定初始化大小時(shí),會給elementData賦值為空集合。
    public ArrayList() {
        // 無參構(gòu)造函數(shù),設(shè)置元素?cái)?shù)組為空
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
常用函數(shù)分析

友情提示
add方法:當(dāng)容量到達(dá)size時(shí)進(jìn)行擴(kuò)容(add(E e)中先調(diào)用了ensureCapacity(size+1)方法,之后將元素的索引賦給elementData[size],而后size自增),擴(kuò)容為當(dāng)前容量的0.5倍(若果ArrayList的當(dāng)前容量為10,那么一次擴(kuò)容后的容量為15)
set方法:調(diào)用set方法時(shí)會檢驗(yàn)索引是否合法(只校驗(yàn)了上限)(index不能等于size(indexget方法:調(diào)用get方法時(shí)也會檢驗(yàn)索引是否合法(只校驗(yàn)了上限)(index不能等于size(indexremove方法:在移除指定下標(biāo)的元素時(shí),會把指定下標(biāo)到數(shù)組末尾的元素向前移動一個(gè)單位,并且會把數(shù)組最后一個(gè)元素設(shè)置為null,這樣是為了方便之后整個(gè)數(shù)組不被使用時(shí),可以被GC;元素移動時(shí)使用的是System.arraycopy()方法

/**
     * 添加元素
     *
     * @param e
     * @return
     */
    public boolean add(E e) {
        //確保elementData數(shù)組有合適的大小
        ensureCapacityInternal(size + 1); 
        elementData[size++] = e;
        return true;
    }

    /**
     * 設(shè)定指定下標(biāo)索引的元素值
     *
     * @param index
     * @param element
     * @return
     */
    public E set(int index, E element) {
        // 檢驗(yàn)索引是否合法
        rangeCheck(index);
        // 舊值
        E oldValue = elementData(index);
        // 賦新值
        elementData[index] = element;
        // 返回舊值
        return oldValue;
    }

    /**
     * 獲取指定下標(biāo)的元素
     *
     * @param index
     * @return
     */
    //說明:get函數(shù)會檢查索引值是否合法(只檢查是否大于size,而沒有檢查是否小于0),
    // 值得注意的是,在get函數(shù)中存在element函數(shù),element函數(shù)用于返回具體的元素 
    public E get(int index) {
        // 檢驗(yàn)索引是否合法
        rangeCheck(index);

        return elementData(index);
    }

    // Positional Access Operations

    /**
     * 位置訪問操作
     *
     * @param index
     * @return
     */
    //說明:返回的值都經(jīng)過了向下轉(zhuǎn)型(Object -> E(泛型))
    @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }

    /**
     * 移除指定下標(biāo)元素
     *
     * @param index
     * @return
     */
    //說明:remove函數(shù)用戶移除指定下標(biāo)的元素
    // 此時(shí)會把指定下標(biāo)到數(shù)組末尾的元素向前移動一個(gè)單位,并且會把數(shù)組最后一個(gè)元素設(shè)置為null,這樣是為了方便之后將整個(gè)數(shù)組不被使用時(shí),可以會被GC。
    //提醒:元素移動時(shí)使用的是System.arraycopy()方法
    public E remove(int index) {
        // 檢查索引是否合法
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);
        // 需要移動的元素的個(gè)數(shù)
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index + 1, elementData, index,
                    numMoved);
        // 賦值為空,有利于進(jìn)行GC
        elementData[--size] = null; // clear to let GC do its work
        // 返回舊值
        return oldValue;
    }

    /**
     * 在指定下標(biāo)位置插入元素
     * @param index
     * @param element
     */
    public void add(int index, E element) {
        //檢查索引是否合法
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1); 
        System.arraycopy(elementData, index, elementData, index + 1,
                size - index);
        elementData[index] = element;
        size++;
    }
其他方法介紹

友情提示:rangeCheckForAdd方法用于add(int index, E element)和addAll(int index, Collection c)方法中檢驗(yàn)索引是否合法;rangeCheck方法用于get、set等方法中檢驗(yàn)索引是否合法(因?yàn)椴桓淖償?shù)據(jù)結(jié)構(gòu),故index不能取到size,最大只能取到size-1)

    //檢驗(yàn)索引是否合法(只校驗(yàn)了上限)(index不能等于size(index= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    //檢驗(yàn)索引是否合法(校驗(yàn)了上限和下限)(index可以等于size(0<=index<=size))
    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    
擴(kuò)容策略
    // 確定ArrarList的容量。
    // 若ArrayList的容量不足以容納當(dāng)前的全部元素,設(shè)置 新的容量=“(原始容量x3)/2 + 1”
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                ? 0
                : DEFAULT_CAPACITY;//默認(rèn)容量10

        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }

    //確保elementData數(shù)組有合適的大小
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {// 判斷元素?cái)?shù)組是否為空數(shù)組
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);// 取較大值
        }
        //確保elemenData數(shù)組有合適的大小
        ensureExplicitCapacity(minCapacity);
    }

    //確保elemenData數(shù)組有合適的大小
    private void ensureExplicitCapacity(int minCapacity) {
        // 結(jié)構(gòu)性修改加1
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    
    //對數(shù)組進(jìn)行擴(kuò)容
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;// 舊容量
        int newCapacity = oldCapacity + (oldCapacity >> 1);// 新容量為舊容量的1.5倍
        if (newCapacity - minCapacity < 0)// 新容量小于參數(shù)指定容量,修改新容量
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)// 新容量大于最大容量
            newCapacity = hugeCapacity(minCapacity);// 指定新容量
        // 拷貝擴(kuò)容
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
    
部分方法測試

add方法

public class AddTest {
    @Test
    public void test1(){
        //我們可以看到,在add方法之前開始elementData = {};
        // 調(diào)用add方法時(shí)會繼續(xù)調(diào)用,直至grow,最后elementData的大小變?yōu)?0,
        // 之后再返回到add函數(shù),把8放在elementData[0]中
        List lists = new ArrayList();
        lists.add(8);
    }

    @Test
    public void test2(){
        //說明:我們可以知道,在調(diào)用add方法之前,elementData的大小已經(jīng)為6,之后再進(jìn)行傳遞,不會進(jìn)行擴(kuò)容處理。
        List lists = new ArrayList(6);//elementData.length=6
        lists.add(8);
    }
    
}

rangeCheck方法

public class RangeCheckTest {
    @Test
    public void test() {
        List list = new ArrayList();
        list.add(1);
        list.add(2);
        list.add(3);
        //該語句報(bào)ArrayIndexOutOfBoundsException異常是rangeCheck(index)引發(fā)的(index >= size)
        System.out.println(list.get(10));
        //rangeCheck(index)方法只校驗(yàn)上線,該語句報(bào)ArrayIndexOutOfBoundsException異常是elementData[index]引發(fā)的
        System.out.println(list.get(-1));
        list.remove(-1);//同上

        Object[] a = new Object[]{1, 2, 3};
        System.out.println(a[-1]);
    }
}

indexOf方法

public class IndexOfTest {
    @Test
    public void test(){
        List list = new ArrayList();
        list.add(null);
        list.add(2);
        list.add(2);
        list.add(null);
        System.out.println(list.indexOf(null));//0
        System.out.println(list.indexOf(2));//1
        System.out.println(list.indexOf(3));//-1
    }
}

toArray方法

public class ToArrayTest {
    @Test
    public void test() {
        List list = new ArrayList(10);
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        Object[] array =list.toArray();
        //調(diào)用Arrays.copyOf()-->調(diào)用System.arraycopy()
    }
}

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

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

相關(guān)文章

  • 這幾道Java集合框架面試題在面試中幾乎必問

    摘要:若遇到哈希沖突,則將沖突的值加到鏈表中即可。之后相比于之前的版本,之后在解決哈希沖突時(shí)有了較大的變化,當(dāng)鏈表長度大于閾值默認(rèn)為時(shí),將鏈表轉(zhuǎn)化為紅黑樹,以減少搜索時(shí)間。有序,唯一紅黑樹自平衡的排序二叉樹。 本文是最最最常見Java面試題總結(jié)系列第三周的文章。主要內(nèi)容: Arraylist 與 LinkedList 異同 ArrayList 與 Vector 區(qū)別 HashMap的底層...

    bigdevil_s 評論0 收藏0
  • java源碼

    摘要:集合源碼解析回歸基礎(chǔ),集合源碼解析系列,持續(xù)更新和源碼分析與是兩個(gè)常用的操作字符串的類。這里我們從源碼看下不同狀態(tài)都是怎么處理的。 Java 集合深入理解:ArrayList 回歸基礎(chǔ),Java 集合深入理解系列,持續(xù)更新~ JVM 源碼分析之 System.currentTimeMillis 及 nanoTime 原理詳解 JVM 源碼分析之 System.currentTimeMi...

    Freeman 評論0 收藏0
  • JDK源碼(容器篇)

    摘要:三系列用于保存鍵值對,無論是,還是已棄用的或者線程安全的等,都是基于紅黑樹。是完全基于紅黑樹的,并在此基礎(chǔ)上實(shí)現(xiàn)了接口??梢钥吹剑挥屑t黑樹,且紅黑樹是通過內(nèi)部類來實(shí)現(xiàn)的。 JDK容器 前言 閱讀JDK源碼有段時(shí)間了,準(zhǔn)備以博客的形式記錄下來,也方便復(fù)習(xí)時(shí)查閱,本文參考JDK1.8源碼。 一、Collection Collection是所有容器的基類,定義了一些基礎(chǔ)方法。List、Se...

    Soarkey 評論0 收藏0
  • Java對象內(nèi)存占用分析

    摘要:對于不同的實(shí)現(xiàn),對象占用的內(nèi)存空間大小可能不盡相同,本文主要分析中的情況,實(shí)驗(yàn)環(huán)境為位系統(tǒng),使用進(jìn)行結(jié)論驗(yàn)證。內(nèi)存占用這里分析一個(gè)只有一組鍵值對的結(jié)構(gòu)如下首先分析本身的大小。 本文深入分析并驗(yàn)證了不同Java對象占用內(nèi)存空間大小的情況。對于不同的jvm實(shí)現(xiàn),Java對象占用的內(nèi)存空間大小可能不盡相同,本文主要分析HotSpot jvm中的情況,實(shí)驗(yàn)環(huán)境為64位window10系統(tǒng)、JD...

    JouyPub 評論0 收藏0
  • Java集合源碼分析系列-(一)ArrayList源碼剖析

    摘要:需要注意的是,通過構(gòu)造函數(shù)定義初始量是動態(tài)數(shù)組的實(shí)際大小。帶容量的構(gòu)造函數(shù)新建一個(gè)容量為的數(shù)組默認(rèn)構(gòu)造函數(shù),默認(rèn)為空構(gòu)造一個(gè)包含指定元素的第一個(gè)構(gòu)造方法使用提供的來初始化數(shù)組的大小。 前言 今天介紹經(jīng)常使用的一個(gè)Java集合類——ArrayList(基于JDK1.8.0_121)。ArrayList在工作和日常面試中經(jīng)常被使用或者提到??偟膩碚f,工作中使用ArrayList主要是因?yàn)閯?..

    Miyang 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<