Java語法進階12-集合

集合

集合:是一種容器,用來裝對象的容器,不能裝基本數據類型。

數組也是容器,可以用來裝基本數據類型,也可以用來裝對象。

本質上,集合需要用對應的數據結構實現,是多個類實現接口Collection系列和Map接口的統稱

Collection

Collection 表示一組對象,這些對象也稱爲 collection 的元素。一些 collection 允許有重複的元素,而另一些則不允許。一些 collection 是有序的,而另一些則是無序的。

Collection<E>是所有單列集合的父接口,因此在Collection中定義了單列集合(List和Set)通用的一些方法,這些方法可用於操作所有的單列集合。

Collection方法:

序號歸類方法簽名方法描述
1 添加 add(E e) 添加一個元素對象到當前集合中
2 添加 addAll(Collection<? extends E> other) 添加多個元素,把other集合的所有元素都添加到當前集合中,this = this ∪ other;
3 刪除 clear() 清空集合
4 刪除 remove(Object obj) 刪除一個元素,根據元素的equals()來判斷是否是要被刪除的元素,如果元素的類型沒有重寫equals方法,那麼等價於==,如果重寫了equals,那麼就按照equals的規則來比較,一般比較內容。
5 刪除 removeAll(Collection<?> coll) 刪除多個元素,把當前集合中和c共同的元素刪除,即this = this - this ∩ coll;子集
6 刪除 retainAll(Collection<?>  coll) 刪除多個元素,在當前集合中保留和c的共同的元素,即this = this ∩ coll;交集
7 int size() 獲取元素的個數
8 boolean contains(Object obj) 是否包含某個元素。根據元素的equals()來判斷是否是要被刪除的元素,如果元素的類型沒有重寫equals方法,那麼等價於==,如果重寫了equals,那麼就按照equals的規則來比較,一般比較內容。
9 boolean containsAll(Collection<?> coll) 是否包含多個元素。判斷當前集合中是否包含coll集合的所有元素,即coll是否是this的子集。
10 boolean isEmpty() 集合是否爲空
11 遍歷 Object[] toArray() 將集合中的元素用數組返回
12 遍歷 Iterator iterator() 返回一個迭代器對象,專門用於遍歷集合

Iterator迭代器

即Collection集合元素的通用獲取方式。每一種實現了Iterable接口的集合內部,都會有一個內部類實現了Iterator接口

  • public boolean hasNext()   【如果仍有元素可以迭代,則返回 true。】

  • public E next()                    【返回迭代的下一個元素。】
  • void remove()                          【使用Iterator迭代器刪除元素】

在調用Iterator的next方法之前,迭代器的索引位於第一個元素之前,指向第一個元素,當第一次調用迭代器的next方法時,返回第一個元素,然後迭代器的索引會向後移動一位,指向第二個元素,依此類推,直到hasNext方法返回false,表示到達了集合的末尾,終止對元素的遍歷。

在進行集合元素取出時,如果集合中已經沒有元素了,還繼續使用迭代器的next方法,將會發生java.util.NoSuchElementException沒有集合元素的錯誤

注意:不要在使用Iterator迭代器進行迭代時,調用Collection的remove(xx)方法,否則會報異常java.util.ConcurrentModificationException,或出現不確定行爲。

增強for

增強for循環(也稱for each循環)是JDK1.5以後出來的一個高級for循環,專門用來遍歷數組和集合的,或者說實現了Iterable接口的其他容器名。

for(元素的數據類型  變量 : Collection集合or數組){
  //寫操作代碼
}

Iterable接口

java.lang.Iterable接口,實現這個接口允許對象成爲 "foreach" 語句的目標。

java.lang.Iterable接口的抽象方法:

  • public Iterator iterator():                        【獲取對應的迭代器】

foreach本質上就是使用Iterator迭代器進行遍歷的。

所以也不要在foreach遍歷的過程使用Collection的remove()方法。

modCount

如果在Iterator、ListIterator迭代器創建後的任意時間從結構上修改了集合(通過迭代器自身的 remove 或 add 方法之外的任何其他方式),則迭代器將拋出 ConcurrentModificationException。這就是Iterator迭代器的快速失敗(fail-fast)機制。

結構性修改是指:改變list的size大小,或者,以其他方式改變他導致正在進行迭代時出現錯誤的結果。

那麼如何實現快速失敗(fail-fast)機制的呢?

  • 在ArrayList等集合類中都有一個modCount變量。它用來記錄集合的結構被修改的次數。

  • 當我們給集合添加和刪除操作時,會導致modCount++。

  • 然後當我們用Iterator迭代器遍歷集合時,創建集合迭代器的對象時,用一個變量記錄當前集合的modCount。例如:int expectedModCount = modCount;,並且在迭代器每次next()迭代元素時,都要檢查 expectedModCount != modCount

注意,迭代器的快速失敗行爲不能得到保證,因此,編寫依賴於此異常的程序的方式是錯誤的,正確做法是:迭代器的快速失敗行爲應該僅用於檢測 bug。

自定義類時如果一個實現類不希望提供fail-fast迭代器,則可以忽略這個字段。

List

List接口特點:

  1. 它是一個元素存取有序的集合。即元素的存入順序和取出順序有保證。

  2. 它是一個帶有索引的集合,通過索引就可以精確的操作集合中的元素(與數組的索引是一個道理)。

  3. 集合中可以有重複的元素,通過元素的equals方法,來比較是否爲重複的元素。

List集合關心元素是否有序,而不關心是否重複

List接口的實現類有很多,常見的有:

ArrayList:動態數組  Vector:動態數組  LinkedList:雙向鏈表  Stack:棧

List除了從Collection集合繼承的方法外,List 集合裏添加了一些根據索引來操作集合元素的方法。

1、添加元素

  • void add(int index, E ele)                                                    【在[index]位置添加一個元素】 

  • boolean addAll(int index, Collection<? extends E> eles)    【在[index]位置添加多個元素】

2、獲取元素

  • E get(int index)                                                                      【返回[index]位置的元素】

  • List subList(int fromIndex, int toIndex)                                  【截取[fromIndex,toIndex)部分的元素】

3、獲取元素索引

  • int indexOf(Object obj)                                                          【返回obj在當前集合中第一次出現的下標】

  • int lastIndexOf(Object obj)                                                    【返回obj在當前集合中最後一次出現的下標】

4、刪除和替換元素

  • E remove(int index)                                                               【刪除[index]位置的元素,返回被刪除的元素】

  • E set(int index, E ele)                                                            【替換[index]位置的元素,返回被替換的元素】 

5、遍歷

在原來Iterator和foreach遍歷的基礎上增加了:

ListIterator listIterator()                                                                   【默認遊標在[0]開始】

ListIterator listIterator(int index)                                                      【默認遊標在[index]位置】

ListIterator

List 集合額外提供了一個 listIterator() 方法,該方法返回一個 ListIterator 對象, ListIterator 接口繼承了 Iterator 接口,提供了專門操作 List 的方法:

  • void add():                                                                         【通過迭代器添加元素到對應集合】

  • void set(E e):                                                                     【用指定元素替換 nextprevious 返回的最後一個元素】

  • void remove():                                                                   【從列表中移除由 nextprevious 返回的最後一個元素】

  • boolean hasPrevious():                                                     【如果以逆向遍歷列表,往前是否還有元素。則返回 true

  • E  previous():                                                                    【返回列表中的前一個元素。】

  • int previousIndex():                                                           【返回列表中的前一個元素的索引】

  • boolean hasNext()                                                               【以正向遍歷列表時,如果列表迭代器有多個元素,則返回 true

  • E  next()                                                                               【返回列表中的下一個元素。】

  • int nextIndex()                                                                      【返回對 next 的後續調用所返回元素的索引。】

Set

set接口沒有提供額外的方法。但是比Collection接口更加嚴格了。

Set 集合不允許包含相同的元素,如果試把兩個相同的元素加入同一個 Set 集合中,則添加操作失敗。

Set集合支持的遍歷方式和Collection集合一樣:foreach和Iterator。

Set集合的實現類:TreeSet:按大小順序,LinkedHashSet:按照添加的順序,HashSet:無序

HashSet

HashSet 是 Set 接口的典型實現,大多數時候使用 Set 集合時都使用這個實現類。

java.util.HashSet底層的實現其實是一個java.util.HashMap支持,然後HashMap的底層物理實現是一個Hash表。

HashSet 集合判斷兩個元素相等的標準:兩個對象通過 hashCode() 方法比較相等,並且兩個對象的 equals() 方法返回值也相等。因此,存儲到HashSet的元素要重寫hashCode和equals方法。

LinkedHashSet

LinkedHashSet是HashSet的子類,它在HashSet的基礎上,在結點中增加兩個屬性before和after維護了結點的前後添加順序。java.util.LinkedHashSet,它是鏈表和哈希表組合的一個數據存儲結構。LinkedHashSet插入性能略低於 HashSet,但在迭代訪問 Set 裏的全部元素時有很好的性能。

HashSet/LinkedHashSet:如何區別元素的不可重複。依賴於元素的hashCode和equals方法

TreeSet

底層結構:裏面維護了一個TreeMap,都是基於紅黑樹實現的!

特點: 1、不允許重複        2、實現排序, 自然排序或定製排序

如果使用的是自然排序(Comparable),則通過調用實現的compareTo方法

自然排序:它判斷兩個對象是否相等的唯一標準是:兩個對象通過 compareTo(T o) 方法比較返回值爲0。

如果使用的是定製排序(Comparator),則通過調用比較器的compare方法

定製排序:使用定製排序判斷兩個元素相等的標準是:通過compare(T o1,T o2)比較兩個元素返回了0。

如果希望保持一致性,在重寫compareTo時,一般也會重寫equals方法。不是語法要求,而且邏輯意義問題。

Collection系列的集合框架圖

Map

Collection中的集合稱爲單列集合,Map中的集合稱爲雙列集合。java.util.Map<K,V>

1、存儲鍵值對(key,value),也稱爲映射關係,鍵值對是Map.Entry接口的實現類對象。

2、所有存儲到Map中的key不能重複, 每個鍵只能對應一個值(這個值可以是單個值,也可以是個數組或集合值)。

3、所有存儲到Map中的value可以重複

Map接口的API

1、添加

V put(K key, V value):                                    【將一對鍵值對添加到當前map中,同一個key如果put兩次,第二次會覆蓋上次的value】

void putAll(Map m):                                        【將另一個map中的所有鍵值對添加到當前map中】

2、刪除

void clear():                                                    【清空所有映射關係】

V remove(Object key):                                   【根據key刪除一整對鍵值對(key,value)】

3、查詢

int size():                                                         【返回鍵值對的數量】

boolean containsKey(Object key):                 【是否包含某個key】

boolean containsValue(Object value):            【是否包含某個value】

V get(Object key):                                          【根據key獲取value值,如果此映射不包含該鍵的映射關係,則返回 null。】

boolean isEmpty()                                       【如果此映射未包含鍵-值映射關係,則返回 true。】

4、遍歷

Set<Entry<K,V>>  entrySet()                            【遍歷所有的鍵值對,映射關係的 Set 視圖 】

Set<K>  keySet()                                              【遍歷所有的key,鍵的 Set 視圖】

Collection<V>  values()                                    【遍歷所有的value,值的 Collection 視圖】

使用put方法時,若指定的鍵(key)在集合中沒有,則沒有這個鍵對應的值,返回null,並把指定的鍵值添加到集合中;

若指定的鍵(key)在集合中存在,則返回值爲集合中鍵對應的值(該值爲替換前的值),並把指定鍵所對應的值,替換成指定的新值。

Map集合的遍歷

 Map的遍歷,不能支持foreach

(1)分開遍歷:

  • 單獨遍歷所有key

  • 單獨遍歷所有value

(2)成對遍歷:

  • 遍歷的是映射關係Map.Entry類型的對象,Map.Entry是Map接口的內部接口。每一種Map內部有自己的Map.Entry的實現類。在Map中存儲數據,實際上是將Key---->value的數據存儲在Map.Entry接口的實例中,再在Map集合中插入Map.Entry的實例化對象

 Map接口的常用實現類:HashMap、TreeMap、LinkedHashMap和Properties。其中HashMap是 Map 接口使用頻率最高的實現類。

HashMap和Hashtable的區別與聯繫

  • HashMap和Hashtable都是哈希表。

  • HashMap和Hashtable判斷兩個 key 相等的標準是:兩個 key 的hashCode 值相等,並且 equals() 方法也返回 true。因此,爲了成功地在哈希表中存儲和獲取對象,用作鍵的對象必須實現 hashCode 方法和 equals 方法。

  • Hashtable是線程安全的,任何非 null 對象都可以用作鍵或值。不允許null鍵

  • HashMap是線程不安全的,並允許使用 null 值和 null 鍵。

LinkedHashMap

LinkedHashMap 是 HashMap 的子類。LinkedHashMap實現與 HashMap 的不同之處在於,LinkedHashMap維護着一個運行於所有條目的雙重鏈接列表。此鏈接列表定義了迭代順序,該迭代順序通常就是將鍵插入到映射中的順序(插入順序)。

TreeMap

基於紅黑樹(Red-Black tree)的 NavigableMap 實現。該映射根據其鍵的自然順序進行排序,或者根據創建映射時提供的 Comparator 進行排序,具體取決於使用的構造方法。

Properties

Properties 類是 Hashtable 的子類,Properties 可保存在中或從流中加載。屬性列表中每個鍵及其對應值都是一個字符串。

存取數據時,建議使用setProperty(String key,String value)方法和getProperty(String key)方法。

更多方法請見API文檔

Set集合與Map集合的關係

Set的內部實現其實是一個Map。即HashSet的內部實現是一個HashMap,TreeSet的內部實現是一個TreeMap,LinkedHashSet的內部實現是一個LinkedHashMap。

咱們存到Set中只有一個元素,又是怎麼變成(key,value)的呢?

原來是,把添加到Set中的元素作爲內部實現map的key,然後用一個常量對象PRESENT對象,作爲value。

集合框架圖

Collections工具類

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章