java容器篇


引言

   第三天卡。。。

  今天主要看了下java容器方面的知識,很累但是很充實。吃兩把雞去了,休息一下,再戰。

開始

    -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。
                   

            - 拉鏈法的工作原理
                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)順序。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM