Java ArrayList 實現(xiàn)實例講解
ArrayList概述:
ArrayList是基于數(shù)組實現(xiàn)的,是一個動態(tài)數(shù)組,其容量能自動增長,類似于C語言中的動態(tài)申請內(nèi)存,動態(tài)增長內(nèi)存。
ArrayList不是線程安全的,只能用在單線程環(huán)境下,多線程環(huán)境下可以考慮用Collections.synchronizedList(List l)函數(shù)返回一個線程安全的ArrayList類,也可以使用concurrent并發(fā)包下的CopyOnWriteArrayList類。
ArrayList實現(xiàn)了Serializable接口,因此它支持序列化,能夠通過序列化傳輸,實現(xiàn)了RandomAccess接口,支持快速隨機訪問,實際上就是通過下標序號進行快速訪問,實現(xiàn)了Cloneable接口,能被克隆。
每個ArrayList實例都有一個容量,該容量是指用來存儲列表元素的數(shù)組的大小。它總是至少等于列表的大小。隨著向ArrayList中不斷添加元素,其容量也自動增長。自動增長會帶來數(shù)據(jù)向新數(shù)組的重新拷貝,因此,如果可預知數(shù)據(jù)量的多少,可在構造ArrayList時指定其容量。在添加大量元素前,應用程序也可以使用ensureCapacity操作來增加ArrayList實例的容量,這可以減少遞增式再分配的數(shù)量。
注意,此實現(xiàn)不是同步的。如果多個線程同時訪問一個ArrayList實例,而其中至少一個線程從結構上修改了列表,那么它必須保持外部同步。
下面對java arraylist做一個記錄和總結吧
public class arraylist<E> { /** * 存放集合的元素 * */ private transient Object[] elementData; /** 元素的大小 */ private int size;
定義了一個泛型類,一個object的數(shù)組和一個私有變量來記錄該集合的元素數(shù)量,原文多了一個私有變量,我也不知道干嘛用的,作者也沒解釋也沒提及到,我沒使用也沒事
/** * 根據(jù)指定大小初始化 * @param initialCapacity */ public arraylist(int initialCapacity){ super(); if(initialCapacity<=0){ //拋異常 throw new IllegalArgumentException("初始化參數(shù)不能小于0"); }else{ //初始化數(shù)組 this.elementData=new Object[initialCapacity]; } } /** * 默認初始化 */ public arraylist(){ this(10); } /** * 根據(jù)一個集合類初始化 * @param c 一個必須繼承了Collection接口的類 */ public arraylist(Collection<? extends E> c){ //初始化 elementData=c.toArray(); size=elementData.length; //如果不是任意類型的數(shù)組就轉換Objec類型 if (elementData.getClass() != Object[].class){ elementData=Arrays.copyOf(elementData,size, Object[].class); } }
3個初始化方法,根據(jù)默認大小進行數(shù)組的初始化,給定大小初始化和傳遞一個繼承了Collection集合接口的類進行轉換賦值初始化
/** * 擴容集合 * @param minCapacity */ public void ensureCapacity(int minCapacity){ /** 當前數(shù)組的大小 */ int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { /** * oldData 雖然沒有被使用,但是這是關于內(nèi)存管理的原因和Arrays.copyOf()方法不是線程安全 * oldData在if的生命周期內(nèi)引用elementData這個變量,所以不會被GC回收掉 * 當Arrays.copyOf()方法在把elementData復制到newCapacity時,就可以防止新的內(nèi)存或是其他線程分配內(nèi)存是elementData內(nèi)存被侵占修改 * 當結束是離開if,oldData周期就結束被回收 */ Object oldData[] = elementData; int newCapacity = (oldCapacity * 3)/2 + 1; //增加50%+1 if (newCapacity < minCapacity) newCapacity = minCapacity; //使用Arrays.copyOf把集合的元素復制并生成一個新的數(shù)組 elementData = Arrays.copyOf(elementData, newCapacity); } }
這是一個核心的方法,集合的擴容,其實是對數(shù)組的擴容,minCapacity集合的大小,進行對比判斷是否應該進行擴容,使用了Arrays.copyOf()方法進行擴容,
原文有進行詳細的解釋,這個方法把第一個參數(shù)的內(nèi)容復制到一個新的數(shù)組中,數(shù)組的大小是第二個參數(shù),并返回一個新的數(shù)組,關于oldData的變量上文有詳細的注釋
/** * 檢查索引是否出界 * @param index */ private void RangeCheck(int index){ if(index > size || index < 0){ throw new IndexOutOfBoundsException("下標超出,Index: " + index + ", Size: " +size); } }
一個下標的檢索是否出 1 /**
* 添加元素 * 將指定的元素添加到集合的末尾 * @param e 添加的元素 * @return */ public boolean add(E e){ ensureCapacity(size+1); elementData[size]=e; size++; return true; }
添加元素,先進行擴容,在賦值,然后元素加一,注意 size+1 字段size并沒有加一,這里進行的是算術的運算,所以在后面才需要進行自增
/** * 添加元素 * 將元素添加到指定的位置 * @param index 指定的索引下標 * @param element 元素 * @return */ public boolean add(int index, E element){ RangeCheck(index); ensureCapacity(size+1); // 將 elementData中從Index位置開始、長度為size-index的元素, // 拷貝到從下標為index+1位置開始的新的elementData數(shù)組中。 // 即將當前位于該位置的元素以及所有后續(xù)元素右移一個位置。 System.arraycopy(elementData, index, elementData, index+1, size-index); elementData[index]=element; size++;//元素加一 return true; }
這里不同的是 System.arraycopy(elementData, index, elementData, index+1, size-index);
這是一個c的內(nèi)部方法,詳細的原文有解釋,這里就不說了,這個也是整個ArrayList的核心所在,也Arrays.copyOf()的內(nèi)部實現(xiàn)原理
/** * 添加全部元素 * 按照指定collection的迭代器所返回的元素順序,將該collection中的所有元素添加到此列表的尾部。 * @param c * @return */ public boolean addAll(Collection < ? extends E>c){ Object[] newElement=c.toArray(); int elementLength=newElement.length; ensureCapacity(size+elementLength); //從newElement 0的下標開始,elementLength個元素,elementData size的下標 System.arraycopy(newElement, 0, elementData, size, elementLength); size+=elementLength; return elementLength!=0; }
基本上其他方法都只是根據(jù)不同的情況進行不同的處理,比如通過接口把數(shù)據(jù)對象傳遞進來然后獲取長度進行擴容,在把數(shù)據(jù)使用System,arraycopy復制到新的數(shù)組中
/** * 指定位置,添加全部元素 * @param index 插入位置的下標 * @param c 插入的元素集合 * @return */ public boolean addAll(int index, Collection<? extends E> c){ if(index > size || index < 0){ throw new IndexOutOfBoundsException("Index: " + index + ", Size: " +size); } Object[] newElement=c.toArray(); int elementLength=newElement.length; ensureCapacity(size+elementLength); int numMoved=size-index; //判斷插入的位置是否在數(shù)組中間 if(numMoved>0){ //把index插入位置的后面的所有元素往后移 //elementData index下標開始的numMoved個元素插入到elementData 的index+elementLength位置 System.arraycopy(elementData, index, elementData, index+elementLength, numMoved); } //把newElement里從0開始的elementLength個元素添加到elementData index開始的位置 System.arraycopy(newElement, 0, elementData, index, elementLength); size += elementLength; return elementLength != 0; } /** * 指定下標賦值 * @param index * @param element * @return */ public E set(int index,E element){ RangeCheck(index); E oldElement=(E)elementData[index]; elementData[index]=element; return oldElement; } /** * 根據(jù)下標取值 * @param index * @return */ public E get(int index){ RangeCheck(index); return (E)elementData[index]; } /** * 根據(jù)下標移除元素 * @param index */ public E remove(int index){ RangeCheck(index); E oldElement=(E)elementData[index]; /** 移除的下標后面的元素數(shù)量 */ int numMoved=size-index-1; //如果在數(shù)組范圍內(nèi)就進行移動 if(numMoved>0) System.arraycopy(elementData, index+1, elementData, index, numMoved); //移除 elementData[--size]=null; return oldElement; } /** * 根據(jù)元素移除 * @param obj * @return */ public boolean remove(Object obj){ //Arraylist允許存放null,所以也要進行判斷處理 if(obj==null){ for(int index=0;index<size;index++){ if(elementData[index]==null){ remove(index); return true; } } }else{ for(int index=0;index<size;index++){ if(obj.equals(elementData[index])){ remove(index); return true; } } } return false; } /** * 根據(jù)下標移除指定范圍內(nèi)的元素 * @param fromIndex 開始 * @param toIndex 結束 */ protected void removeRange(int fromIndex, int toIndex){ RangeCheck(fromIndex); RangeCheck(toIndex); //要移動的元素數(shù) int numMoved = size - toIndex; //把toIndex后面的元素移動到fromIndex System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved); //要移除的元素數(shù)量 int newSize=size-(toIndex-fromIndex); while(size!=newSize){ elementData[--size]=null; } } /** * 把數(shù)組容量調整到實際的容量 */ public void trimToSize(){ int leng=elementData.length; if(size<leng){ Object[] old=elementData; elementData=Arrays.copyOf(elementData, size); } } /** * 把集合元素轉換成數(shù)組 * @return */ public Object[] toArray(){ return Arrays.copyOf(elementData, size); } public <T>T[] toArray(T[] a){ if(a.length<size){ return (T[]) Arrays.copyOf(elementData,size, a.getClass()); } //把集合元素復制到a數(shù)組中 System.arraycopy(elementData, 0, a, 0, size); if (a.length > size){ for(int index=size;index<a.length;index++){ a[index] = null; } } return a; }
基本上都是對數(shù)組進行操作和使用c的方法進行賦值移動等,詳細的可以查看原文,原文中除了那個私有變量外也沒多少問題,代碼可以完美運行,這李要注意的和難點就會是System,arraycopy和Arrayist.copy()這2個方法
和在擴容方法里oldData這個變量的使用,這個變量真的很好,一開始我也不知道為什么要這么使用,在原文的末尾會進行解釋。
以上所述是小編給大家介紹的Java ArrayList 實現(xiàn)實例講解,希望對大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會及時回復大家的,在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關文章
JavaWeb使用Session和Cookie實現(xiàn)登錄認證
本篇文章主要介紹了JavaWeb使用Session和Cookie實現(xiàn)登錄認證,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-03-03Java面試題沖刺第十二天--數(shù)據(jù)庫(2)
這篇文章主要為大家分享了最有價值的三道數(shù)據(jù)庫面試題,涵蓋內(nèi)容全面,包括數(shù)據(jù)結構和算法相關的題目、經(jīng)典面試編程題等,感興趣的小伙伴們可以參考一下2021-07-07SSH框架網(wǎng)上商城項目第20戰(zhàn)之在線支付平臺
這篇文章主要為大家詳細介紹了SSH框架網(wǎng)上商城項目第20戰(zhàn)之在線支付平臺,關于第三方支付的內(nèi)容從本文開始,感興趣的小伙伴們可以參考一下2016-06-06mybatis類型轉換器如何實現(xiàn)數(shù)據(jù)加解密
這篇文章主要介紹了mybatis類型轉換器如何實現(xiàn)數(shù)據(jù)加解密,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09Java數(shù)據(jù)結構之隊列(動力節(jié)點Java學院整理)
隊列(Queue)是只允許在一端進行插入,而在另一端進行刪除的運算受限的線性表。 這篇文章詳細給大家介紹了java數(shù)據(jù)結構之隊列,感興趣的朋友跟隨小編一起學習吧2017-04-04java中CompletableFuture異步執(zhí)行方法
本文主要介紹了java中CompletableFuture異步執(zhí)行方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-06-06Java獲取網(wǎng)絡文件并插入數(shù)據(jù)庫的代碼
抓取各大網(wǎng)站的數(shù)據(jù)插入數(shù)據(jù)庫,這樣就不用為沒有數(shù)據(jù)而煩惱了2010-06-06SpringBoot整合EasyExcel?3.x的完整示例
EasyExcel 是一個基于 Java 的、快速、簡潔、解決大文件內(nèi)存溢出的 Excel 處理工具,它能讓你在不用考慮性能、內(nèi)存的等因素的情況下,快速完成 Excel 的讀、寫等功能,這篇文章主要介紹了SpringBoot整合EasyExcel3.x的過程,需要的朋友可以參考下2023-07-07