摘要:隨機訪問數據是相對于順序訪問數據而言,例如鏈表的形式。方法將容器中的元素轉化為數組的形式。在函數中,對容量每次擴展的大小,并且會檢查是否會超過設定的最大數組長度。如果長度超過了限定值,則以原容量為底線,返回一個最大容量。
ArrayList繼承自AbstractList,AbstractList為“random access”的數組提供了基本的實現。隨機訪問數據是相對于順序訪問數據而言,例如鏈表的形式。AbstractSequentialList為鏈表形式的順序訪問提供了基本實現。AbstractList提供了默認的隨機訪問數據的iterator。AbstractList繼承自AbstractCollection,AbstractCollection為Collection提供了基本實現。
java.util.AbstractCollection
containsAbstractCollection實現了查詢是否包含某一個元素的方法。最好使用Iterator遍歷集合中的元素,因為可以屏蔽集合內部元素存儲的具體實現,并且根據不同的數據存儲特點,優化訪問策略。這里還可以正確查找null元素,需要注意的是對null元素的查詢需要特別的處理,有時候自己實現方法時,往往會忽略傳入參數為null時的處理,導致方法無法處理特殊情況。
public boolean contains(Object o) { IteratortoArrayit = iterator(); if (o==null) { while (it.hasNext()) if (it.next()==null) return true; } else { while (it.hasNext()) if (o.equals(it.next())) return true; } return false; }
toArray方法將容器中的元素轉化為數組的形式。這里元素的復制,采用的是直接復制引用。這里還考慮到了并發運算時,元素數量在復制時產生變化的情況,當數量減少時,就用Arrays.copy()截取結果。當數量增加時,會調用finishToArray函數擴容。
public Object[] toArray() { // Estimate size of array; be prepared to see more or fewer elements Object[] r = new Object[size()]; Iteratorit = iterator(); for (int i = 0; i < r.length; i++) { if (! it.hasNext()) // fewer elements than expected return Arrays.copyOf(r, i); r[i] = it.next(); } return it.hasNext() ? finishToArray(r, it) : r; }
在finishToArray函數中,對容量每次擴展1/2+1的大小,并且會檢查是否會超過設定的最大數組長度MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8。如果長度超過了限定值,則以原容量+1為底線,返回一個最大容量。最后返回的數組也會修剪掉多余的位置。
private staticT[] finishToArray(T[] r, Iterator> it) { int i = r.length; while (it.hasNext()) { int cap = r.length; if (i == cap) { int newCap = cap + (cap >> 1) + 1; // overflow-conscious code if (newCap - MAX_ARRAY_SIZE > 0) newCap = hugeCapacity(cap + 1); r = Arrays.copyOf(r, newCap); } r[i++] = (T)it.next(); } // trim if overallocated return (i == r.length) ? r : Arrays.copyOf(r, i); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError ("Required array size too large"); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
這里有一個toArray的重載,需要傳入一個數組作為參數,據我觀察,目的是將集合中的元素存入指定的數組,重利用已有數組的存儲。如果元素過多,而目標數組容納不下,只能重新申請數組來進行存儲。
publicremoveAllT[] toArray(T[] a) { // Estimate size of array; be prepared to see more or fewer elements int size = size(); T[] r = a.length >= size ? a : (T[])java.lang.reflect.Array .newInstance(a.getClass().getComponentType(), size); Iterator it = iterator(); for (int i = 0; i < r.length; i++) { if (! it.hasNext()) { // fewer elements than expected if (a == r) { //利用的原數組,且元素不足,則補null表示結束 r[i] = null; // null-terminate } else if (a.length < i) { //元素較少,但數量超過原始數組,只能用新數組 return Arrays.copyOf(r, i); } else { //元素減少,導致原始數組可以容納下,則copy回原始數組,折騰唄 System.arraycopy(r, 0, a, 0, i); if (a.length > i) { a[i] = null; } } return a; } r[i] = (T)it.next(); } // more elements than expected return it.hasNext() ? finishToArray(r, it) : r; }
removeAll方法刪除目標集合中的所有重疊元素。Iterator可以做到在遍歷時,安全的刪除元素,而通過index循環刪除則可能導致index偏移。
public boolean removeAll(Collection> c) { Objects.requireNonNull(c); boolean modified = false; Iterator> it = iterator(); while (it.hasNext()) { if (c.contains(it.next())) { it.remove(); modified = true; } } return modified; }toString
AbstractCollection的toString實現,比較令我震驚的是e == this的作用。這里為什么要判斷打印的內容是否為自己本身?因為sb.append(e == this ? "(this Collection)" : e);會調用e的toString函數來生成字符串,若不加判斷,則會形成無限的toString遞歸調用。我猜想一下,估計當時toString的實現者沒有注意到該問題的存在,直到該bug出現,腦洞不大還真難想起來這個問題。
public String toString() { Iteratorit = iterator(); if (! it.hasNext()) return "[]"; StringBuilder sb = new StringBuilder(); sb.append("["); for (;;) { E e = it.next(); sb.append(e == this ? "(this Collection)" : e); if (! it.hasNext()) return sb.append("]").toString(); sb.append(",").append(" "); } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/67735.html
摘要:說一說迭代器通過集合對象獲取其對應的對象判斷是否存在下一個元素取出該元素并將迭代器對象指向下一個元素取出元素的方式迭代器。對于使用容器者而言,具體的實現不重要,只要通過容器獲取到該實現的迭代器的對象即可,也就是方法。 前言 歡迎關注微信公眾號:Coder編程獲取最新原創技術文章和相關免費學習資料,隨時隨地學習技術知識!** 本章主要介紹Collection集合相關知識,結合面試中會提到...
摘要:容器相關的操作及其源碼分析說明本文是基于分析的。通常,我們通過迭代器來遍歷集合。是接口所特有的,在接口中,通過返回一個對象。為了偷懶啊,底層使用了迭代器。即返回的和原在元素上保持一致,但不可修改。 容器相關的操作及其源碼分析 說明 1、本文是基于JDK 7 分析的。JDK 8 待我工作了得好好研究下。Lambda、Stream。 2、本文會貼出大量的官方注釋文檔,強迫自己學英語,篇幅...
摘要:值得注意的是,的迭代器是否要調用方法是由要刪除的目標是否數組的元素決定的,如果不存在這樣的元素,則下面的代碼并不會出現異常, java.util.Arrays$ArrayList(下文:Arrays$ArrayList)是java.util.Arrays的私有靜態內部類,他實現的接口,繼承的父類幾乎和java.util.ArrayList(下文:ArrayList)相同,既然是私有的,...
摘要:加載因子是哈希表在其容量自動增加之前可以達到多滿的一種尺度。當哈希表中的條目數超出了加載因子與當前容量的乘積時,則要對該哈希表進行操作即重建內部數據結構,從而哈希表將具有大約兩倍的桶數。成員變量每個對由封裝,存在了對象數組中。 雖是讀書筆記,但是如轉載請注明出處 http://segmentfault.com/blog/exploring/ .. 拒絕伸手復制黨 LinkedLis...
摘要:它主要做了件事初始化容器,并將元素添加到容器里維護這樣我們再調用的方法直接就返回了,不需要再次遍歷和統計的過程。維護實時的維護,及時刪除總結整體上是對底層的二次封裝,很好的處理了各種細節,比如子容器的判空處理,的計算效率,的維護等。 在日常開發中我們通常有需要對 List 容器進行分組的情況,比如對下面的list數據根據name字段來進行分組: [ { date...
閱讀 3190·2023-04-26 03:06
閱讀 3689·2021-11-22 09:34
閱讀 1134·2021-10-08 10:05
閱讀 3024·2021-09-22 15:53
閱讀 3530·2021-09-14 18:05
閱讀 1387·2021-08-05 09:56
閱讀 1880·2019-08-30 15:56
閱讀 2124·2019-08-29 11:02