1. 程式人生 > >Java基礎整理之Java集合

Java基礎整理之Java集合

Java集合框架

常用API:

    boolean addAll();

    int binarySearch(List<?extends Comparable<? super T>> list, T key)

    int binarySearch(List list,T key, Comparator c)

    boolean    disjoint(Collection<?> c1, Collection<?>c2) 判斷重複

    void copy(List<? superT> dest, List<? extends T> src) src 到dest

    int frequency(Collection<?>c, Object o)

    void fill(List<? super T>list, T obj)

    T max(Collection<?extends T> coll)

    T max(Collection<?extends T> coll, Comparator<? super T> comp)

    T min(Collection<?extends T> coll)

    T min(Collection<?extends T> coll, Comparator<? super T> comp)

    booleanreplaceAll(List<T> list, T oldVal, T newVal)

    void reverse(List<?>list)

    Collection<T>     synchronizedCollection(Collection<T>c)

    void   swap(List<?> list, int i, int j) 交換

    void   sort(List<T> list) 排序

    void   shuffle(List<?> list) 打亂排序


    List 按照插入順序儲存元素,有下標,可插入Null

    int size() 返回list中元素個數

    booleancontains(Object o) 判斷list中書否存在此物件

    boolean containsAll(Collection<?>c) 判斷list中是否存在此容器,無關順序

    booleanisEmpty() 判斷lis中元素個數是否為0

    Iterator<E>iterator() 返回Iterator物件

    Object[]toArray() 返回陣列

    <T>T[] toArray(T[] a) 產生制定型別的陣列

    booleanadd(E e) 將此物件新增到list末尾

    voidadd(int index, E element) 在指定位置插入元素,下表不能超過size

    booleanaddAll(Collection<? extends E> c) 在list末尾新增一個容器

    boolean addAll(int index, Collection<? extends E> c) 在指定位置插入容器,下表不能超過size

    booleanremove(Object o) 從list中移除物件

    E remove(intindex) 根據下標移除物件

    booleanremoveAll(Collection<?> c) 移除容器

    booleanretainAll(Collection<?> c) 是否交集

    voidsort(Comparator<? super E> c) 使用特定比較器排序

    voidclear() 清空list

    Eget(int index) 根據下表獲得物件

    Eset(int index, E element) 設定特定位置的物件

    intindexOf(Object o) 返回物件的下標

    intlastIndexOf(Object o) 返回物件最後一次出現的下標

    List<E>subList(int fromIndex, int toIndex) 擷取list

 

List

    ArrayList:採用陣列實現,預設大小為10,第一次add的時候分配記憶體空間,以後沒此擴充套件為之前的1.5倍。隨機訪問速度快。

LinkedList:採用連結串列實現,增加刪除速度快。

兩個List都為非執行緒安全,要使用執行緒安全的List可以使用Collections中的執行緒安全方法將List轉為執行緒安全的。

當經常需要根據下標進行操作時,使用ArrayList。不需要進行下標操作時,使用LinkedList。

 

Set 沒有下標,不能儲存重複的元素,有些能儲存null,有些不能

add(E)

addAll(Collection<?extends E>)

clear()

contains(Object)

containsAll(Collection<?>)

equals(Object)

hashCode()

isEmpty()

iterator()

remove(Object)

removeAll(Collection<?>)

retainAll(Collection<?>)

size()

spliterator()

toArray()

toArray(T[])

    測試歸屬性,詢問某個物件是否在set中,set是基於物件的值來去頂歸屬性的;查詢是set最重要操作;Set和Collection介面完全一樣;輸出順序沒有規律。

    HashSet使用雜湊函式,最快獲取元素的方式。使用HashMap實現。

    TreeSet將元素儲存在紅-黑數結構中。按照比較結果的升序儲存物件。使用TreeMap實現。

1. 關於hashCode和equals的處理,遵循如下規則:

1) 只要重寫equals,就必須重寫hashCode。

2) 因為Set儲存的是不重複的物件,依據hashCode和equals進行判斷,所以Set儲存的物件必須重寫這兩個方法。

3) 如果自定義物件做為Map的鍵,那麼必須重寫hashCode和equals。 正例:String重寫了hashCode和equals方法,所以我們可以非常愉快地使用String物件作為key來使用。

 

2. ArrayList的subList結果不可強轉成ArrayList,否則會丟擲ClassCastException異常:java.util.RandomAccessSubList cannot becast to java.util.ArrayList ;

說明:subList 返回的是 ArrayList 的內部類 SubList,並不是 ArrayList ,而是原ArrayList的一個子集,對於SubList 子列表的所有操作最終會反映到原列表上。對原集合元素個數的修改,會導致子列表的遍歷、增加、刪除均產生ConcurrentModificationException 異常。

3. 使用集合轉陣列的方法,必須使用集合的toArray(T[] array),傳入的是型別完全一樣的陣列,大小就是 list.size()。

說明:使用 toArray 帶參方法,入參分配的陣列空間不夠大時,toArray 方法內部將重新分配記憶體空間,並返回新陣列地址;如果陣列元素大於實際所需,下標為[ list.size()]的陣列元素將被置為 null,其它陣列元素保持原值,因此最好將方法入引數組大小定義與集合元素個數一致。

 

4. 使用工具類 Arrays.asList()把陣列轉換成集合時,不能使用其修改集合相關的方法,它的 add/remove/clear 方法會丟擲 UnsupportedOperationException 異常。

說明:asList 的返回物件是一個 Arrays 內部類,並沒有實現集合的修改方法。Arrays.asList體現的是介面卡模式,只是轉換介面,後臺的資料仍是陣列。建立一個新的List,使用addAll()方法進行新增,也可使用Collections.addAll()方法新增。

 

 

5. 不要在 foreach 迴圈裡進行元素的 remove/add 操作。remove 元素請使用 Iterator方式,如果併發操作,需要對Iterator 物件加鎖。

 

6. 集合初始化時,儘量指定集合初始值大小。(集合擴容效率問題)

7. 使用 entrySet 遍歷 Map 類集合 KV,而不是 keySet 方式進行遍歷。

說明:keySet 其實是遍歷了 2 次,一次是轉為 Iterator 物件,另一次是從 hashMap 中取出key 所對應的 value。而 entrySet 只是遍歷了一次就把 key 和 value 都放到了 entry 中,效率更高。如果是 JDK8,使用 Map.foreach 方法。

8. 高度注意 Map 類集合 K/V 能不能儲存 null 值的情況,如下表格:

9. 利用 Set 元素唯一的特性,可以快速對一個集合進行去重操作,避免使用 List 的contains 方法進行遍歷、對比、去重操作

 (1) HashMap:遍歷順序不確定,允許一條記錄的鍵為null,允許多條記錄的值為null。非執行緒安全,如果需要滿足執行緒安全,可以用 Collections的synchronizedMap方法使HashMap具有執行緒安全的能力,或者使用ConcurrentHashMap。

(2) Hashtable:Hashtable是遺留類,承自Dictionary類,執行緒安全的併發性不如ConcurrentHashMap,因為ConcurrentHashMap引入了分段鎖。Hashtable不建議在新程式碼中使用,不需要執行緒安全的場合可以用HashMap替換,需要執行緒安全的場合可以用ConcurrentHashMap替換。

(3) LinkedHashMap:LinkedHashMap是HashMap的一個子類,儲存了記錄的插入順序,在用Iterator遍歷LinkedHashMap時,先得到的記錄肯定是先插入的,也可以在構造時帶引數,按照訪問次序排序。

(4) TreeMap:TreeMap實現SortedMap介面,能夠把它儲存的記錄根據鍵排序,預設是按鍵值的升序排序,也可以指定排序的比較器,當用Iterator遍歷TreeMap時,得到的記錄是排過序的。如果使用排序的對映,建議使用TreeMap。在使用TreeMap時,key必須實現Comparable介面或者在構造TreeMap傳入自定義的Comparator,否則會在執行時丟擲java.lang.ClassCastException型別的異常。

對於上述四種Map型別的類,要求對映中的key是不可變物件。不可變物件是該物件在建立後它的雜湊值不會被改變。如果物件的雜湊值發生變化,Map物件很可能就定位不到對映的位置了。

HashMap:

實現結構:陣列+連結串列(當連結串列長度>=8時,連結串列轉換為紅黑樹)(JDK1.8),使用雜湊表來儲存的,

採用了鏈地址法解決衝突,兩個key會定位到相同的位置,表示發生了Hash碰撞。當然Hash演算法計算結果越分散均勻,Hash碰撞的概率就越小,map的存取效率就會越高。如果雜湊桶陣列很大,即使較差的Hash演算法也會比較分散,如果雜湊桶陣列陣列很小,即使好的Hash演算法也會出現較多碰撞,所以就需要在空間成本和時間成本之間權衡,

Node陣列預設初始長度length為16,負載因子Loadfactor預設大小為0.75。這兩個陣列可以在建立HashMap時通過建構函式傳參進行控制。threshold是HashMap所能容納的最大資料量的Node(鍵值對)個數。threshold = length * Load factor。當map中的數目的值要超過threshold時,map將進行重新resize(擴容),擴容後的HashMap容量是之前容量的兩倍。

實現:

1.  確定雜湊桶陣列索引位置

a)  (key == null) ? 0 : (h =key.hashCode()) ^ (h >>> 16);

h & (length - 1)

2.  分析HashMap的put方法



3.  擴容機制

陣列大小 * 2