標籤:指標 dex rand 基於 欄位 可重複 類型 fir 添加
容器
-Collection 儲存物件的集合;Map 儲存索引值對的映射表
-Iterator(迭代器模式)
-集合訪問器,用於逐一查看集合中的對象
-所有實現了Collection介面的容器類都有iterator方法,用於返回一個實現了Iterator介面的對象。Iterator對象稱作迭代器,Iterator介面方法能以迭代方式逐個訪問集合中各個元素,並可以從Collection中除去適當的元素
-Collection
-set(特徵:無序且不可重複)
-TreeSet:基於紅/黑樹狀結構實現,支援有序性操作,例如根據一個範圍尋找元素的操作。但是尋找效率不如 HashSet,HashSet 尋找的時間複雜度為 O(1),TreeSet 則為 O(logN)。
-HashSet:基於雜湊表實現,支援快速尋找,但不支援有序性操作。並且失去了元素的插入順序資訊,也就是說使用 Iterator 遍曆 HashSet 得到的結果是不確定的
-LinkedHashSet:具有 HashSet 的尋找效率,且內部使用雙向鏈表維護元素的插入順序
-紅/黑樹狀結構:漫畫看懂紅/黑樹狀結構 連結:https://www.sohu.com/a/201923614_466939
-list(特徵:有序且可重複)
-ArrayList:基於動態數組實現,支援隨機訪問。
-概覽
-實現了 RandomAccess 介面,因此支援隨機訪問。這是理所當然的,因為 ArrayList 是基於數組實現的,其數組的預設大小為 10。
-序列化
-基於數組實現,並且具有動態擴容特性,因此儲存元素的數組不一定都會被使用,那麼就沒必要全部進行序列
transient Object[] A; //transient關鍵字聲明數組預設不會被序列化
-為什麼定義A數組要用transient關鍵字修飾,使其預設不被序列化?
假如現在實際有了5個元素,而elementData的大小可能是10,那麼在序列化時只需要儲存5個元素,數組中的最後五個元素是沒有實際意義的,不需要儲存。所以ArrayList的設計者將elementData設計為transient,然後在writeObject方法中手動將其序列化,並且只序列化了實際儲存的那些元素,而不是整個數組
-序列化時需要使用 ObjectOutputStream 的 writeObject() 將對象轉換為位元組流並輸出。而 writeObject() 方法在傳入的對象存在 writeObject() 的時候會去反射調用該對象的 writeObject() 來實現序列化。還原序列化使用的是 ObjectInputStream 的 readObject() 方法,原理類似。
-java中序列化的目的:
-以某種儲存形式使自訂對象持久化;
-將對象從一個地方傳遞到另一個地方。
-使程式更具維護性
-擴容
-添加元素時使用 ensureCapacityInternal() 方法來保證容量足夠,如果不夠時,需要使用 grow() 方法進行擴容,新容量的大小為 oldCapacity + (oldCapacity >> 1),也就是舊容量的 1.5 倍
-擴容操作需要調用 Arrays.copyOf() 把原數組整個複製到新數組中,這個操作代價很高,因此最好在建立 ArrayList 對象時就指定大概的容量大小,減少擴容操作的次數
-刪除元素
-需要調用 System.arraycopy() 將 index+1 後面的元素都複製到 index 位置上,該操作的時間複雜度為 O(N), ArrayList 刪除元素的代價是非常高的。
-fail-fast
-modCount 用來記錄 ArrayList 結構發生變化的次數。結構發生變化是指添加或者刪除至少一個元素的所有操作,或者是調整內部數組的大小,僅僅只是設定元素的值不算結構發生變化
-在進行序列化或者迭代等操作時,需要比較操作前後 modCount 是否改變,如果改變了需要拋出 ConcurrentModificationException。
-fail-fast與fail-safe
-fail-fast
-fail-fast機制在遍曆一個集合時,當集合結構被修改,會拋出ConcurrentModificationException。
-java.util包下的集合類都是快速失敗的,不能在多線程下發生並發修改(迭代過程中被修改)。
-fail-safe
-fail-safe任何對集合結構的修改都會在一個複製的集合上進行修改,不像fail-fast在原集合上修改,因此不會拋出ConcurrentModificationException
-java.util.concurrent包下的容器都是安全失敗,可以在多線程下並發使用,並發修改。
-優點
-避免了ConcurrentModificationException
-缺點
-需要複製集合,產生大量的無效對象,開銷大
-無法保證讀取的資料是目前未經處理資料結構中的資料。
-迭代器並不能訪問到修改後的內容,即:迭代器遍曆的是開始遍曆那一刻拿到的集合拷貝,在遍曆期間原集合發生的修改迭代器是不知道的。
-Vector:和 ArrayList 類似,但它是安全執行緒的。
-它的實現與 ArrayList 類似,但是使用了 synchronized 進行同步。因此是安全執行緒的
-與ArrayList比較
-Vector 是同步的,因此開銷就比 ArrayList 要大,訪問速度更慢。最好使用 ArrayList 而不是 Vector,因為同步操作完全可以由程式員自己來控制;
-Vector 每次擴容請求其大小的 2 倍空間,而 ArrayList 是 1.5 倍。
-LinkedList:基於雙向鏈表實現,只能順序訪問,但是可以快速地在鏈表中間插入和刪除元素。不僅如此,LinkedList 還可以用作棧、隊列和雙向隊列。
-概覽
-基於雙向鏈表實現,使用 Node 儲存鏈表節點資訊。
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
}
每個鏈表格儲存體了 first 和 last 指標
transient Node<E> first;
transient Node<E> last;
-與 ArrayList 的比較
-ArrayList 基於動態數組實現,LinkedList 基於雙向鏈表實現;
-ArrayList 支援隨機訪問,LinkedList 不支援;
-LinkedList 在任意位置添加刪除元素更快。
-Map
-TreeMap:基於紅/黑樹狀結構實現
-HashMap:基於雜湊表實現。
-儲存結構
-內部包含了一個 Entry 類型的數組 table。
transient Entry[] table;
Entry 儲存著索引值對。它包含了四個欄位,從 next 欄位我們可以看出 Entry 是一個鏈表。即數組中的每個位置被當成一個桶,一個桶存放一個鏈表。HashMap 使用拉鏈法來解決衝突,同一個鏈表中存放雜湊值相同的 Entry。
{{{{{{{entry結構圖}}}}}}}
- 拉鏈法的工作原理
HashMap<String, String> map = new HashMap<>();
map.put("K1", "V1");
map.put("K2", "V2");
map.put("K3", "V3");
建立一個 HashMap,預設大小為 16;
插入 <K1,V1> 索引值對,先計算 K1 的 hashCode 為 115,使用除留餘數法得到所在的桶下標 115%16=3。
插入 <K2,V2> 索引值對,先計算 K2 的 hashCode 為 118,使用除留餘數法得到所在的桶下標 118%16=6。
插入 <K3,V3> 索引值對,先計算 K3 的 hashCode 為 118,使用除留餘數法得到所在的桶下標 118%16=6,插在 <K2,V2> 前面。
-應該注意到鏈表的插入是以頭插法方式進行的,例如上面的 <K3,V3> 不是插在 <K2,V2> 後面,而是插入在鏈表頭部。
-尋找需要分成兩步進行:
-計算索引值對所在的桶;
-在鏈表上順序尋找,時間複雜度顯然和鏈表的長度成正比。
-put操作
-HashMap 允許插入鍵為 null 的索引值對。但是因為無法調用 null 的 hashCode() 方法,也就無法確定該索引值對的桶下標,只能通過強制指定一個桶下標來存放。HashMap 使用第 0 個桶存放鍵為 null 的索引值對。
-確定桶下標
-擴容
-基本原理
-重新計算桶下標
-計算數組容量
-鏈錶轉紅/黑樹狀結構
-從 JDK 1.8 開始,一個桶儲存的鏈表長度大於 8 時會將鏈錶轉換為紅/黑樹狀結構
-與 HashTable 的比較
HashTable 使用 synchronized 來進行同步。
HashMap 可以插入鍵為 null 的 Entry。
HashMap 的迭代器是 fail-fast 迭代器。
HashMap 不能保證隨著時間的推移 Map 中的元素次序是不變的。
-HashTable:和 HashMap 類似,但它是安全執行緒的,這意味著同一時刻多個線程可以同時寫入 HashTable 並且不會導致資料不一致。它是遺留類,不應該去使用它。現在可以使用 ConcurrentHashMap 來支援安全執行緒,並且 ConcurrentHashMap 的效率會更高,因為 ConcurrentHashMap 引入了分段鎖。
-LinkedHashMap:使用雙向鏈表來維護元素的順序,順序為插入順序或者最近最少使用(LRU)順序。
java容器篇