摘要:部分源碼分析小記底層數(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ù)組的。
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(index
/** * 添加元素 * * @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 extends E> 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擴(kuò)容策略= 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)); }
// 確定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]中 Listlists = 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
摘要:若遇到哈希沖突,則將沖突的值加到鏈表中即可。之后相比于之前的版本,之后在解決哈希沖突時(shí)有了較大的變化,當(dāng)鏈表長度大于閾值默認(rèn)為時(shí),將鏈表轉(zhuǎn)化為紅黑樹,以減少搜索時(shí)間。有序,唯一紅黑樹自平衡的排序二叉樹。 本文是最最最常見Java面試題總結(jié)系列第三周的文章。主要內(nèi)容: Arraylist 與 LinkedList 異同 ArrayList 與 Vector 區(qū)別 HashMap的底層...
摘要:三系列用于保存鍵值對,無論是,還是已棄用的或者線程安全的等,都是基于紅黑樹。是完全基于紅黑樹的,并在此基礎(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...
摘要:對于不同的實(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...
摘要:需要注意的是,通過構(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)閯?..
閱讀 2502·2021-08-11 11:16
閱讀 2941·2019-08-30 15:55
閱讀 3342·2019-08-30 12:53
閱讀 1584·2019-08-29 13:28
閱讀 3273·2019-08-28 18:17
閱讀 949·2019-08-26 12:19
閱讀 2476·2019-08-23 18:27
閱讀 717·2019-08-23 18:17