java function获取参数_「Java容器」ArrayList源码,大厂面试必问
- ArrayList簡介
- ArrayList核心源碼
- ArrayList源碼分析
- System.arraycopy()和Arrays.copyOf()方法
- 兩者聯(lián)系與區(qū)別
- ArrayList核心擴(kuò)容技術(shù)
- 內(nèi)部類
- ArrayList經(jīng)典Demo
ArrayList簡介
ArrayList 的底層是數(shù)組隊(duì)列,相當(dāng)于動態(tài)數(shù)組。與 Java 中的數(shù)組相比,它的容量能動態(tài)增長。在添加大量元素前,應(yīng)用程序可以使用ensureCapacity操作來增加 ArrayList 實(shí)例的容量。這可以減少遞增式再分配的數(shù)量。
它繼承于 AbstractList,實(shí)現(xiàn)了 List, RandomAccess, Cloneable, java.io.Serializable 這些接口。
在我們學(xué)數(shù)據(jù)結(jié)構(gòu)的時候就知道了線性表的順序存儲,插入刪除元素的時間復(fù)雜度為O(n),求表長以及增加元素,取第 i 元素的時間復(fù)雜度為O(1)
ArrayList 繼承了AbstractList,實(shí)現(xiàn)了List。它是一個數(shù)組隊(duì)列,提供了相關(guān)的添加、刪除、修改、遍歷等功能。
ArrayList 實(shí)現(xiàn)了RandomAccess 接口, RandomAccess 是一個標(biāo)志接口,表明實(shí)現(xiàn)這個這個接口的 List 集合是支持快速隨機(jī)訪問的。在 ArrayList 中,我們即可以通過元素的序號快速獲取元素對象,這就是快速隨機(jī)訪問。
ArrayList 實(shí)現(xiàn)了Cloneable 接口,即覆蓋了函數(shù) clone(),能被克隆。
ArrayList 實(shí)現(xiàn)java.io.Serializable 接口,這意味著ArrayList支持序列化,能通過序列化去傳輸。
和 Vector 不同,ArrayList 中的操作不是線程安全的!所以,建議在單線程中才使用 ArrayList,而在多線程中可以選擇 Vector 或者 CopyOnWriteArrayList。
ArrayList核心源碼
package java.util;import java.util.function.Consumer;import java.util.function.Predicate;import java.util.function.UnaryOperator;public class ArrayList extends AbstractList implements List, RandomAccess, Cloneable, java.io.Serializable{ private static final long serialVersionUID = 8683452581122892189L; /** * 默認(rèn)初始容量大小 */ private static final int DEFAULT_CAPACITY = 10; /** * 空數(shù)組(用于空實(shí)例)。 */ private static final Object[] EMPTY_ELEMENTDATA = {}; //用于默認(rèn)大小空實(shí)例的共享空數(shù)組實(shí)例。 //我們把它從EMPTY_ELEMENTDATA數(shù)組中區(qū)分出來,以知道在添加第一個元素時容量需要增加多少。 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; /** * 保存ArrayList數(shù)據(jù)的數(shù)組 */ transient Object[] elementData; // non-private to simplify nested class access /** * ArrayList 所包含的元素個數(shù) */ private int size; /** * 帶初始容量參數(shù)的構(gòu)造函數(shù)。(用戶自己指定容量) */ public ArrayList(int initialCapacity) { if (initialCapacity > 0) { //創(chuàng)建initialCapacity大小的數(shù)組 this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { //創(chuàng)建空數(shù)組 this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } /** *默認(rèn)構(gòu)造函數(shù),DEFAULTCAPACITY_EMPTY_ELEMENTDATA 為0.初始化為10,也就是說初始其實(shí)是空數(shù)組 當(dāng)添加第一個元素的時候數(shù)組容量才變成10 */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } /** * 構(gòu)造一個包含指定集合的元素的列表,按照它們由集合的迭代器返回的順序。 */ public ArrayList(Collection extends E> c) { // elementData = c.toArray(); //如果指定集合元素個數(shù)不為0 if ((size = elementData.length) != 0) { // c.toArray 可能返回的不是Object類型的數(shù)組所以加上下面的語句用于判斷, //這里用到了反射里面的getClass()方法 if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // 用空數(shù)組代替 this.elementData = EMPTY_ELEMENTDATA; } } /** * 修改這個ArrayList實(shí)例的容量是列表的當(dāng)前大小。 應(yīng)用程序可以使用此操作來最小化ArrayList實(shí)例的存儲。 */ public void trimToSize() { modCount++; if (size < elementData.length) { elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } }//下面是ArrayList的擴(kuò)容機(jī)制//ArrayList的擴(kuò)容機(jī)制提高了性能,如果每次只擴(kuò)充一個,//那么頻繁的插入會導(dǎo)致頻繁的拷貝,降低性能,而ArrayList的擴(kuò)容機(jī)制避免了這種情況。 /** * 如有必要,增加此ArrayList實(shí)例的容量,以確保它至少能容納元素的數(shù)量 * @param minCapacity 所需的最小容量 */ public void ensureCapacity(int minCapacity) { int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) // any size if not default element table ? 0 // larger than default for default empty table. It's already // supposed to be at default size. : DEFAULT_CAPACITY; if (minCapacity > minExpand) { ensureExplicitCapacity(minCapacity); } } //得到最小擴(kuò)容量 private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // 獲取默認(rèn)的容量和傳入?yún)?shù)的較大值 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } //判斷是否需要擴(kuò)容 private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) //調(diào)用grow方法進(jìn)行擴(kuò)容,調(diào)用此方法代表已經(jīng)開始擴(kuò)容了 grow(minCapacity); } /** * 要分配的最大數(shù)組大小 */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /** * ArrayList擴(kuò)容的核心方法。 */ private void grow(int minCapacity) { // oldCapacity為舊容量,newCapacity為新容量 int oldCapacity = elementData.length; //將oldCapacity 右移一位,其效果相當(dāng)于oldCapacity /2, //我們知道位運(yùn)算的速度遠(yuǎn)遠(yuǎn)快于整除運(yùn)算,整句運(yùn)算式的結(jié)果就是將新容量更新為舊容量的1.5倍, int newCapacity = oldCapacity + (oldCapacity >> 1); //然后檢查新容量是否大于最小需要容量,若還是小于最小需要容量,那么就把最小需要容量當(dāng)作數(shù)組的新容量, if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //再檢查新容量是否超出了ArrayList所定義的最大容量, //若超出了,則調(diào)用hugeCapacity()來比較minCapacity和 MAX_ARRAY_SIZE, //如果minCapacity大于MAX_ARRAY_SIZE,則新容量則為Interger.MAX_VALUE,否則,新容量大小則為 MAX_ARRAY_SIZE。 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); } //比較minCapacity和 MAX_ARRAY_SIZE private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } /** *返回此列表中的元素?cái)?shù)。 */ public int size() { return size; } /** * 如果此列表不包含元素,則返回 true 。 */ public boolean isEmpty() { //注意=和==的區(qū)別 return size == 0; } /** * 如果此列表包含指定的元素,則返回true 。 */ public boolean contains(Object o) { //indexOf()方法:返回此列表中指定元素的首次出現(xiàn)的索引,如果此列表不包含此元素,則為-1 return indexOf(o) >= 0; } /** *返回此列表中指定元素的首次出現(xiàn)的索引,如果此列表不包含此元素,則為-1 */ public int indexOf(Object o) { if (o == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { for (int i = 0; i < size; i++) //equals()方法比較 if (o.equals(elementData[i])) return i; } return -1; } /** * 返回此列表中指定元素的最后一次出現(xiàn)的索引,如果此列表不包含元素,則返回-1。. */ public int lastIndexOf(Object o) { if (o == null) { for (int i = size-1; i >= 0; i--) if (elementData[i]==null) return i; } else { for (int i = size-1; i >= 0; i--) if (o.equals(elementData[i])) return i; } return -1; } /** * 返回此ArrayList實(shí)例的淺拷貝。 (元素本身不被復(fù)制。) */ public Object clone() { try { ArrayList> v = (ArrayList>) super.clone(); //Arrays.copyOf功能是實(shí)現(xiàn)數(shù)組的復(fù)制,返回復(fù)制后的數(shù)組。參數(shù)是被復(fù)制的數(shù)組和復(fù)制的長度 v.elementData = Arrays.copyOf(elementData, size); v.modCount = 0; return v; } catch (CloneNotSupportedException e) { // 這不應(yīng)該發(fā)生,因?yàn)槲覀兪强梢钥寺〉?throw new InternalError(e); } } /** *以正確的順序(從第一個到最后一個元素)返回一個包含此列表中所有元素的數(shù)組。 *返回的數(shù)組將是“安全的”,因?yàn)樵摿斜聿槐A魧λ囊谩?(換句話說,這個方法必須分配一個新的數(shù)組)。 *因此,調(diào)用者可以自由地修改返回的數(shù)組。 此方法充當(dāng)基于陣列和基于集合的API之間的橋梁。 */ public Object[] toArray() { return Arrays.copyOf(elementData, size); } /** * 以正確的順序返回一個包含此列表中所有元素的數(shù)組(從第一個到最后一個元素); *返回的數(shù)組的運(yùn)行時類型是指定數(shù)組的運(yùn)行時類型。 如果列表適合指定的數(shù)組,則返回其中。 *否則,將為指定數(shù)組的運(yùn)行時類型和此列表的大小分配一個新數(shù)組。 *如果列表適用于指定的數(shù)組,其余空間(即數(shù)組的列表數(shù)量多于此元素),則緊跟在集合結(jié)束后的數(shù)組中的元素設(shè)置為null 。 *(這僅在調(diào)用者知道列表不包含任何空元素的情況下才能確定列表的長度。) */ @SuppressWarnings("unchecked") public T[] toArray(T[] a) { if (a.length < size) // 新建一個運(yùn)行時類型的數(shù)組,但是ArrayList數(shù)組的內(nèi)容 return (T[]) Arrays.copyOf(elementData, size, a.getClass()); //調(diào)用System提供的arraycopy()方法實(shí)現(xiàn)數(shù)組之間的復(fù)制 System.arraycopy(elementData, 0, a, 0, size); if (a.length > size) a[size] = null; return a; } // Positional Access Operations @SuppressWarnings("unchecked") E elementData(int index) { return (E) elementData[index]; } /** * 返回此列表中指定位置的元素。 */ public E get(int index) { rangeCheck(index); return elementData(index); } /** * 用指定的元素替換此列表中指定位置的元素。 */ public E set(int index, E element) { //對index進(jìn)行界限檢查 rangeCheck(index); E oldValue = elementData(index); elementData[index] = element; //返回原來在這個位置的元素 return oldValue; } /** * 將指定的元素追加到此列表的末尾。 */ public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! //這里看到ArrayList添加元素的實(shí)質(zhì)就相當(dāng)于為數(shù)組賦值 elementData[size++] = e; return true; } /** * 在此列表中的指定位置插入指定的元素。 *先調(diào)用 rangeCheckForAdd 對index進(jìn)行界限檢查;然后調(diào)用 ensureCapacityInternal 方法保證capacity足夠大; *再將從index開始之后的所有成員后移一個位置;將element插入index位置;最后size加1。 */ public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! //arraycopy()這個實(shí)現(xiàn)數(shù)組之間復(fù)制的方法一定要看一下,下面就用到了arraycopy()方法實(shí)現(xiàn)數(shù)組自己復(fù)制自己 System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; } /** * 刪除該列表中指定位置的元素。 將任何后續(xù)元素移動到左側(cè)(從其索引中減去一個元素)。 */ 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; } /** * 從列表中刪除指定元素的第一個出現(xiàn)(如果存在)。 如果列表不包含該元素,則它不會更改。 *返回true,如果此列表包含指定的元素 */ 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; } /* * Private remove method that skips bounds checking and does not * return the value removed. */ 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 } /** * 從列表中刪除所有元素。 */ public void clear() { modCount++; // 把數(shù)組中所有的元素的值設(shè)為null for (int i = 0; i < size; i++) elementData[i] = null; size = 0; } /** * 按指定集合的Iterator返回的順序?qū)⒅付现械乃性刈芳拥酱肆斜淼哪┪病?*/ public boolean addAll(Collection extends E> c) { Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); // Increments modCount System.arraycopy(a, 0, elementData, size, numNew); size += numNew; return numNew != 0; } /** * 將指定集合中的所有元素插入到此列表中,從指定的位置開始。 */ public boolean addAll(int index, Collection extends E> c) { rangeCheckForAdd(index); Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); // Increments modCount int numMoved = size - index; if (numMoved > 0) System.arraycopy(elementData, index, elementData, index + numNew, numMoved); System.arraycopy(a, 0, elementData, index, numNew); size += numNew; return numNew != 0; } /** * 從此列表中刪除所有索引為fromIndex (含)和toIndex之間的元素。 *將任何后續(xù)元素移動到左側(cè)(減少其索引)。 */ protected void removeRange(int fromIndex, int toIndex) { modCount++; int numMoved = size - toIndex; System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved); // clear to let GC do its work int newSize = size - (toIndex-fromIndex); for (int i = newSize; i < size; i++) { elementData[i] = null; } size = newSize; } /** * 檢查給定的索引是否在范圍內(nèi)。 */ private void rangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } /** * add和addAll使用的rangeCheck的一個版本 */ private void rangeCheckForAdd(int index) { if (index > size || index < 0) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } /** * 返回IndexOutOfBoundsException細(xì)節(jié)信息 */ private String outOfBoundsMsg(int index) { return "Index: "+index+總結(jié)
以上是生活随笔為你收集整理的java function获取参数_「Java容器」ArrayList源码,大厂面试必问的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux gdb 破解软件密码
- 下一篇: @springbootapplicati