日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

arraylist是如何扩容的?_ArrayList的源码分析

發布時間:2025/3/21 编程问答 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 arraylist是如何扩容的?_ArrayList的源码分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

ArrayList的類定義

public class ArrayList extends AbstractList implements List, RandomAccess, Cloneable, java.io.Serializable{

實現 List 接口,繼承了 AbstractList 抽象類,這個是很好理解的,ArrayList作為List集合類家族的一部分,可以更好的將公用方法抽象給上層

實現Cloneable和Serializable接口?,可以進行克隆和序列化操作

實現RandomAccess接口,這個接口會相對陌生點,點進去官方給的解釋是,RandomAccess是一個標記接口,是一個空接口,僅起到標記的作用(類似Serializable接口)

public interface RandomAccess {}

List實現這個接口表明這個類能實現?快速隨機訪問。該接口的主要目的是允許通用算法更改其行為,以便在應用于隨機訪問或順序訪問列表時提供良好的性能

而后文檔里給了說明,如果實現了RandomAccess接口,對List做查詢操作時使用for循環的方式,否則使用迭代器的方式。這樣做的原因做了RandomAccess接口標記的LIst實現類底層數據結構使用for循環效率更高(比如ArrayList),沒有RandomAccess接口標記的使用迭代器效率更高(比如LinkedList,下文可以看到LinkedList沒有實現RandomAccess接口)

舉個簡單的小例子,比如Collections類里的二分查找方法,就是用是否標記了RandomAccess接口來區分用哪種方法實現的:

public static int binarySearch(List extends Comparable super T>> list, T key) { if (list instanceof RandomAccess || list.size() return Collections.indexedBinarySearch(list, key); // for循環方法 else return Collections.iteratorBinarySearch(list, key); // Iterator循環方法}

ArrayList構造函數

public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

ArrayList實現了三種構造函數用于不同情形下的對象創建

a. 無參構造了一個空數組,在首次添加元素的時候才給數據設置大小的構造函數

b.?給定初始容量的構造函數,通過參數 initialCapacity 可設置List數組的初始大小,這樣做的好處是當 ArrayList 新增元素時,如果所存儲的元素已經超過其已有大小,它會計算元素大小后再進行動態擴容,數組的擴容會導致整個數組進行一次內存復制。因此,我們在初始化 ArrayList 時,可以通過第一個構造函數合理指定數組初始大小,這樣有助于減少數組的擴容次數,從而提高系統性能

public ArrayList(int initialCapacity) { if (initialCapacity > 0) { // initialCapacity大于0,數組的大小為initialCapacity值 this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { // initialCapacity等于0,生成默認空數組EMPTY_ELEMENTDATA this.elementData = EMPTY_ELEMENTDATA; } else { // 其他情況,報非法參數異常-》數組的大小必須大于等于0 throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); }}

c.傳入Collection對象轉化成ArrayList,將 Collection 轉化為數組并賦值給 elementData,把 elementData 中元素的個數賦值給 size。如果 size 不為零,則判斷 elementData 的 class 類型是否為 Object[],不是的話則做一次轉換。如果 size 為零,則把 EMPTY_ELEMENTDATA 賦值給 elementData,相當于new ArrayList(0)

public ArrayList(Collection extends E> c) { Object[] a = c.toArray(); if ((size = a.length) != 0) { if (c.getClass() == ArrayList.class) { elementData = a; } else { elementData = Arrays.copyOf(a, size, Object[].class); } } else { // replace with empty array. elementData = EMPTY_ELEMENTDATA; }}

ArrayList屬性

transient Object[] elementData; // non-private to simplify nested class accessprivate static final int DEFAULT_CAPACITY = 10;private int size;

elementData?:底層數組,用來存儲數據

DEFAULT_CAPACITY?:數組的默認初始化容量 10

size?:當前的數組大小,用來表示當前數組包含了多少個元素

ArrayList新增元素

/** * 直接將元素添加到數組尾部 */public boolean add(E e) { // 1.判斷當前數組容量是否夠用,不夠的話進行數組擴容操作 ensureCapacityInternal(size + 1); // Increments modCount!! // 2.將元素添加到數組尾部,size加1 elementData[size++] = e; return true;}/** * 將元素添加到指定位置 */public void add(int index, E element) { // 1.判斷指定位置是否在數組包含范圍內 rangeCheckForAdd(index); // 2.判斷當前數組容量是否夠用,不夠的話進行數組擴容操作 ensureCapacityInternal(size + 1); // Increments modCount!! // 3.將指定位置開始的元素向后挪動一位 System.arraycopy(elementData, index, elementData, index + 1, size - index); // 4.將元素添加到指定位置上 elementData[index] = element; size++;}

ArrayList提供了兩種添加元素的方法,第一種:直接將元素添加到數組尾部;第二種:將元素添加到指定位置

從代碼里可以看出,兩種添加方式都執行了 ensureCapacityInternal 方法,判斷數組的容量情況,具體看下這個方法是如何實現的呢:

判斷當前數組是否是空數組EMPTY_ELEMENTDATA,如果是的話,判斷默認值(10)和傳入的容量(size+1)誰大,就返回哪個,如果不是空數組的話,直接返回(size+1),這一步是對初始化為空數組的情況進行特殊處理

判斷傳入容量(size+1)是否大于當前的數組大小,如果是的話進行擴容操作(grow)

擴容操作是將容量擴充到原始容量的1.5倍大小,如果還是不夠,就將容量給定為當前傳入的容量(size+1)

這里需要判斷下是否有內存溢出的問題,當容量達到允許的最大值(MAX_ARRAY_SIZE)的時候,將數組容量給定為int最大值

擴容后需要將原數組重新分配到新的內存地址中

/** * 計算數組容量,從傳入的容量和默認容量(10)里面去較大的 */private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity;}/** * 計算數組容量,從傳入的容量和默認容量(10)里面去較大的 */private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));}/** * 計算數組容量,如果傳入容量比當前數組已有元素數量小,需要進行擴容操作 */private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity);}/** * 數組擴容 */private void grow(int minCapacity) { // 計算擴容后的數組容量 // overflow-conscious code int oldCapacity = elementData.length; // 擴容后新的容量是原容量的1.5倍 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);}/** * 數據容量大小邊界處理 */private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;}/** * 數據允許的最大容量 */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

從代碼里可以看到,添加元素到任意位置,會導致在該位置后的所有元素都需要重新排列,而將元素添加到數組的末尾,在沒有發生擴容的前提下,是不會有元素復制排序過程的。所以直接將元素添加的數組的末尾效率會更高

ArrayList查找元素

public E get(int index) { // 檢查index是否越界, rangeCheck(index); // 返回數組對應下標元素值 return elementData(index);}private void rangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}@SuppressWarnings("unchecked")E elementData(int index) { return (E) elementData[index];}

ArrayList在數據查找上的效率很高,只需要O(1)的時間復雜度就能獲取數據,傳入需要元素的下標index,返回數據中的對應元素即可

ArrayList刪除元素

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

ArrayList刪除元素的代碼邏輯和添加元素到任意位置的方法類似,在每一次有效的刪除元素操作之后,都要進行數組的重組,并且刪除的元素位置越靠前,數組重組的開銷就越大

  • 判斷index是否合法(有沒有下標越界)

  • 獲取要刪除的元素

  • 將要刪除數據下標往后的元素向前移動一位

  • 將最后一位置零

  • 返回被刪除的元素

  • 今天的分享就到這里,一起學技術,一起在生活中探險~歡迎關注【小肖愛吃肉】

    總結

    以上是生活随笔為你收集整理的arraylist是如何扩容的?_ArrayList的源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 九九爱爱视频 | 麻豆 美女 丝袜 人妻 中文 | 最新自拍偷拍 | 国产伦理一区二区三区 | 日韩国产片| 91动态图 | 在线亚洲一区二区 | 久久一区二 | 国产精品视频久久 | 欧美三级中文字幕 | 一级午夜 | 亚洲AV无码阿娇国产精品 | 在线观看国产网站 | 成人亚洲精品久久久久软件 | 国产一区二区欧美日韩 | 亚洲无码精品一区二区三区 | 亚洲free性xxxx护士白浆 | 黄色wwww| 黑人三级视频 | jizz91| 高清一区二区三区四区五区 | 亚洲综合色av | 亚洲免费网站在线观看 | 久草中文在线观看 | 成人听书哪个软件好 | 国产肉体ⅹxxx137大胆 | 色综合久久88色综合天天免费 | 人妻精品一区二区三区 | 日韩一区二区不卡视频 | 久久精品无码Av中文字幕 | 色九月婷婷 | 91久久人人 | 免费观看的黄色网址 | 2019国产精品视频 | 久久久久看片 | 一区二区视频在线看 | 亚洲天堂手机版 | 国产在线播| 精人妻无码一区二区三区 | 日韩免费精品 | av网站一区 | 日韩卡一卡二 | 91久久国产综合久久91精品网站 | 日韩av中文| 自拍 偷拍 欧美 | 亚洲理伦电影 | 特大黑人娇小亚洲女mp4 | 欧美十大老熟艳星 | 高潮又黄又刺激 | 综合网婷婷 | 在线免费看毛片 | 亚洲欧美激情在线 | 欧美爱爱网站 | 国产aⅴ片 | 日本污视频在线观看 | 一级裸体片 | 欧美乱大交 | youjizz日韩| 欧美激情一区二区在线 | 91精品国产视频 | 最新中文字幕在线播放 | 亚洲色图欧美日韩 | 亚欧在线 | 日本系列第一页 | 综合人人 | 亚洲美女高潮久久久 | 亚洲性欧美色 | 日批视频免费看 | 国产乱淫av麻豆国产 | 日韩不卡毛片 | 九色在线观看视频 | 国产经典一区 | 国产精品suv一区二区三区 | 乱色熟女综合一区二区三区 | 夜夜躁很很躁日日躁麻豆 | 一进一出视频 | 黄色长视频 | 日韩欧美在线观看一区二区 | 国产性猛交普通话对白 | 亚洲福利天堂 | 国产精品手机在线 | 轮乱 | 99精品视频网站 | 国产精品18久久久久久vr下载 | 视频一区二区三区四区五区 | 九一国产在线观看 | 91色视频在线 | 九九九久久久 | 国产精品国产一区二区 | 国产欧美激情在线观看 | 亚洲av毛片基地 | 国产精品无遮挡 | 亚洲精品7777 | 伊人快播| 3d动漫精品啪啪一区二区免费 | 深爱激情五月婷婷 | 日韩视频 中文字幕 | av在线免费观看一区 | 久久精品免费看 |