Java集合框架的總結整理

源出處:尚硅谷:http://www.gulixueyuan.com/my/course/310

Java集合框架的總結整理

  1. Java集合框架概述

Java集合框架概述

  • 一方面, 面嚮對象語言對事物的體現都是以對象的形式,爲了方便對多個對象 的操作,就要對對象進行存儲。另一方面,使用Array存儲對象方面具有一些弊 端,而Java 集合就像一種容器,可以動態地把多個對象的引用放入容器中。
    • 數組在內存存儲方面的特點:
      1. 數組初始化以後,長度就確定了。
      2. 數組聲明的類型,就決定了進行元素初始化時的類型
    • 數組在存儲數據方面的弊端:
      1. 數組初始化以後,長度就不可變了,不便於擴展
      2. 數組中提供的屬性和方法少,不便於進行添加、刪除、插入等操作,且效率不高。 同時無法直接獲取存儲元素的個數
      3. 數組存儲的數據是有序的、可以重複的。【存儲數據的特點單一】
  • Java 集合類可以用於存儲數量不等的多個對象,還可用於保存具有映射關係的關聯數組。

Java 集合可分爲 Collection 和 Map 兩種體系

  • Collection接口:單列數據,定義了存取一組對象的方法的集合

    • List:元素有序、可重複的集合【“動態”數組,替換原有的數組】
      • ArrayList:作爲List接口的主要實現類;線程不安全的,效率高;底層數據結構是數組,使用Object[ ]存儲
      • LinkedList:對於頻繁的插入、刪除操作,使用此類效率比ArrayList高;底層使用雙向鏈表存儲
      • Vector:作爲List接口的古老實現類;線程安全的,效率低;底層是數組,使用Object[]存儲
    • Set:元素無序、不可重複的集合
      • HashSet:作爲Set接口的主要實現類;線程不安全的;可以存儲null值;底層是HashMap,底層數據結構是哈希表(即數組+鏈表),使用hash算法計算存儲位置。

      • LinkedHashSet:作爲HashSet的子類;遍歷其內部數據時,可以按照添加的順序遍歷;對於頻繁的遍歷操作,LinkedHashSet效率高於HashSet,底層數據結構是鏈表和哈希表。使用hash算法計算存儲位置,同時使用鏈表來維護順序,順序與添加順序一致

      • TreeSet:可以按照添加對象的指定屬性,進行排序。底層是二叉樹【紅黑樹】

  • Map接口:雙列數據,保存具有映射關係“key-value對”的集合
    Map常用實現類:

    • HashMap::HashMap是 Map 接口使用頻率最高的實現類,允許使用 null 值和 null 鍵;此類不保證映射的順序;在多線程操作下不安全,底層數據結構是 jdk1.7:哈希表(數組+鏈表),jdk1.8:哈希表(數組+鏈表)+紅黑樹
    • LinkedHashMap:在HashMap存儲結構的基礎上,使用了一對雙向鏈表來記錄添加
      元素的順序,雙向鏈表的數據結構保證了該集合具有可預知的迭代順序(有序性)
    • TreeMap:TreeMap存儲 Key-Value 對時,需要根據 key-value 對進行排序。 TreeMap 可以保證所有的 Key-Value 對處於有序狀態
    • Hashtable:Hashtable是個古老的 Map 實現類,JDK1.0就提供了。不同於HashMap, Hashtable是線程安全的。Hashtable實現原理和HashMap相同,功能相同。底層都使用哈希表結構,查詢 速度快,很多情況下可以互用。
    • Properties:Properties 類是 Hashtable 的子類,該對象用於處理屬性文件

Collection接口繼承樹:在這裏插入圖片描述Map接口繼承樹:
在這裏插入圖片描述


Collection 接口

  • Collection 接口是 List、Set 和 Queue 接口的父接口,該接口裏定義的方法 既可用於操作 Set 集合,也可用於操作 List 和 Queue 集合。
  • JDK不提供此接口的任何直接實現,而是提供更具體的子接口(如:Set和List)實現。
  • 在 Java5 之前,Java 集合會丟失容器中所有對象的數據類型,把所有對象都 當成 Object 類型處理;從 JDK 5.0 增加了泛型以後,Java 集合可以記住容器中對象的數據類型。

Collection 接口方法

https://blog.csdn.net/qq_40164190/article/details/106506910

Collection子接口之一:List接口

List接口概述:

  • 鑑於Java中數組用來存儲數據的侷限性,我們通常使用List替代數組
  • List集合類中元素有序、且可重複,集合中的每個元素都有其對應的順序索引。
  • List容器中的元素都對應一個整數型的序號記載其在容器中的位置,可以根據 序號存取容器中的元素。
  • JDK API中List接口的實現類常用的有:ArrayList、LinkedList和Vector。

List接口常用方法

https://blog.csdn.net/qq_40164190/article/details/106431687

List實現類之一:ArrayList

  • ArrayList 是 List 接口的典型實現類、主要實現類(即用得最多、最頻繁)
  • ArrayList是一個可變長數組,無容量的限制(超出容量後會自動擴容)
  • 線程不安全的,會出現 fail-fast,效率高;底層使用Object類型的數組Object[]存儲

ArrayList的源碼分析:(詳細源碼分析及擴容機制請點擊這裏)

jdk 1.7情況下
ArrayList list = new ArrayList();//底層創建了長度是10的Object[]數組elementData
list.add(123);//elementData[0] = new Integer(123);

list.add(11);//如果此次的添加導致底層elementData數組容量不夠,則擴容。
默認情況下,擴容爲原來的容量的1.5倍,同時需要將原有數組中的數據複製到新的數組中。

jdk 1.8中ArrayList的變化:
ArrayList list = new ArrayList();//底層Object[] elementData初始化爲{}.並沒有創建長度爲10的數組
list.add(123);//第一次調用add()時,底層才創建了長度10的數組,並將數據123添加到elementData[0]
後續擴容操作與jdk1.8一致

小結:建議開發中使用帶參的構造器:ArrayList list = new ArrayList(int capacity)
在jdk1.8中,第一次調用add()時,底層才創建了長度10的數組。
jdk7中的ArrayList的對象的創建類似於單例模式的餓漢式,而jdk8中的ArrayList的對象的創建類似於單例模式的懶漢式,延遲了數組的創建,節省內存。

List實現類之二:LinkedList

  • LinkedList是一個繼承於AbstractSequentialList的雙向鏈表。它也可以被當做堆棧、隊列或雙端隊列進行使用。
  • 對於頻繁的插入或刪除元素的操作,建議使用LinkedList類,效率較高
  • LinkedList 中的操作不是線程安全的
  • LinkedList:雙向鏈表,內部沒有聲明數組,而是定義了Node類型的first和last, 用於記錄首末元素。同時,定義內部類Node,作爲LinkedList中保存數據的基本結構。Node除了保存數據,還定義了兩個變量:
    • prev變量記錄前一個元素的位置
    • next變量記錄下一個元素的位置
    private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

在這裏插入圖片描述

  • 新增方法:
void addFirst(Object obj)
void addLast(Object obj)
Object getFirst() 
Object getLast() 
Object removeFirst() 
Object removeLast()

List實現類之三:Vector

  • Vector 是一個古老的集合,JDK1.0就有了。Vector 類實現了一個動態數組。和 ArrayList 很相似,區別之處在於:
    • Vector 是同步訪問的所以是Vector是線程安全的
    • Vector 包含了許多傳統的方法,這些方法不屬於集合框架。
  • 在各種list中,最好把ArrayList作爲默認選擇。當插入、刪除頻繁時, 使用LinkedList;Vector總是比ArrayList慢,所以儘量避免使用

Collection子接口之二:Set接口

Set接口概述

  • Set接口是Collection的子接口,Set與Collection基本上完全一樣,因爲Set接口中沒有額外提供新的方法,使用的都是Collection中聲明過的方法。實際上Set就是Collection,只是行爲略有不同(Set不允許包含重複元素)。
  • Set 集合不允許包含相同的元素,如果試把兩個相同的元素加入同一個 Set 集合中,則添加操作失敗。
  • Set 判斷兩個對象是否相同不是使用 == 運算符,而是根據 equals() 方法

Set實現類之一:HashSet

  • HashSet 是 Set 接口的典型實現,大多數時候使用 Set 集合時都使用這個實現類。
  • HashSet 按 Hash 算法來存儲集合中的元素,因此具有很好的存取、查找、刪除 性能。
  • HashSet 具有以下特點
    • 不能保證元素的排列順序(無序性)
    • 不可重複性
    • HashSet 不是線程安全的
    • 集合元素可以是 null
  • HashSet 集合判斷兩個元素相等的標準:兩個對象通過 hashCode() 方法比較相 等,並且兩個對象的 equals() 方法返回值也相等。
  • 對於存放在Set容器中的對象,對應的類一定要重寫equals()和hashCode(Object obj)方法,以實現對象相等規則。即:“相等的對象必須具有相等的散列碼”
HashSet集合存儲數據的結構(哈希表)

什麼是哈希表呢?

在JDK1.8之前,哈希表底層採用數組+鏈表實現,即使用鏈表處理衝突,同一hash值的鏈表都存儲在一個鏈表裏。但是當位於一個桶中的元素較多,即hash值相等的元素較多時,通過key值依次查找的效率較低。而JDK1.8中,哈希表存儲採用數組+鏈表+紅黑樹實現,當鏈表長度超過閾值(8)時,將鏈表轉換爲紅黑樹,這樣大大減少了查找時間。

簡單的來說,哈希表是由數組+鏈表+紅黑樹(JDK1.8增加了紅黑樹部分)實現的。

JDK1.8引入紅黑樹大程度優化了HashMap的性能,那麼對於我們來講保證HashSet集合元素的唯一,其實就是根據對象的hashCode和equals方法來決定的。如果我們往集合中存放自定義的對象,那麼保證其唯一,就必須複寫hashCode和equals方法建立屬於當前對象的比較方式。

添加元素的過程:以HashSet爲例:

當向 HashSet 集合中存入一個元素時,HashSet 會調用該對象的 hashCode() 方法 來得到該對象的 hashCode 值,

然後根據 hashCode 值,通過某種散列函數決定該對象 在 HashSet 底層數組中的存儲位置。
	- 這個散列函數會與底層數組的長度相計算得到在數組中的下標,
	- 並且這種散列函數計算還儘可能保證能均勻存儲元素,越是散列分佈, 該散列函數設計的越好

如果兩個元素的hashCode()值相等,會再繼續調用equals方法,
	如果equals方法結果 爲true,添加失敗;
	如果爲false,那麼會保存該元素,但是該數組的位置已經有元素了, 那麼會通過鏈表的方式繼續鏈接。

如果兩個元素的 equals() 方法返回 true,但它們的 hashCode() 返回值不相等:
	hashSet 將會把它們存儲在不同的位置,但依然可以添加成功

Set實現類之二:LinkedHashSet

  • LinkedHashSet 是 HashSet 的子類
  • LinkedHashSet 根據元素的 hashCode 值來決定元素的存儲位置, 但它同時使用雙向鏈表維護元素的次序,這使得元素看起來是以插入順序保存的。
  • LinkedHashSet插入性能略低於 HashSet,但在迭代訪問 Set 裏的全部元素時有很好的性能。【即對於頻繁的遍歷操作, LinkedHashSet效率高於HashSet】
  • LinkedHashSet 不允許集合元素重複

Set實現類之三:TreeSet

  • TreeSet 是 SortedSet 接口的實現類,TreeSet 可以確保集合元素處於排序狀態。
  • TreeSet底層使用紅黑樹結構存儲數
  • 新增的方法如下: (瞭解)
    Comparator comparator()
    Object first() Object last() 
    Object lower(Object e) 
    Object higher(Object e) 
    SortedSet subSet(fromElement, toElement)
    SortedSet headSet(toElement)
    SortedSet tailSet(fromElement)
    
  • TreeSet 兩種排序方法:自然排序和定製排序。默認情況下,TreeSet 採用自然排序。
    在這裏插入圖片描述
排 序—自然排序
  • 自然排序:TreeSet 會調用集合元素的 compareTo(Object obj) 方法來比較元素之間的大小關係,然後將集合元素按升序(默認情況)排列
  • 如果試圖把一個對象添加到 TreeSet 時,則該對象的類必須實現 Comparable 接口。
    • 實現 Comparable 的類必須實現 compareTo(Object obj) 方法,兩個對象即通過 compareTo(Object obj) 方法的返回值來比較大小。
  • Comparable 的典型實現:
    • BigDecimal、BigInteger 以及所有的數值型對應的包裝類:按它們對應的數值大小 進行比較
    • Character:按字符的 unicode值來進行比較
    • Boolean:true 對應的包裝類實例大於 false 對應的包裝類實例
    • String:按字符串中字符的 unicode 值進行比較
    • Date、Time:後邊的時間、日期比前面的時間、日期
  • 向 TreeSet 中添加元素時,只有第一個元素無須比較compareTo()方法,後面添 加的所有元素都會調用compareTo()方法進行比較。
  • 因爲只有相同類的兩個實例纔會比較大小,所以向 TreeSet 中添加的應該是同 一個類的對象。
  • 對於 TreeSet 集合而言,它判斷兩個對象是否相等的唯一標準是:兩個對象通 過 compareTo(Object obj) 方法比較返回值。
  • 當需要把一個對象放入 TreeSet 中,重寫該對象對應的 equals() 方法時,應保證該方法與 compareTo(Object obj) 方法有一致的結果:如果兩個對象通過 equals() 方法比較返回 true,則通過 compareTo(Object obj) 方法比較應返回 0。
排 序—定製排序
  • TreeSet的自然排序要求元素所屬的類實現Comparable接口,如果元素所屬的類沒 有實現Comparable接口,或不希望按照升序(默認情況)的方式排列元素或希望按照 其它屬性大小進行排序,則考慮使用定製排序。定製排序,通過Comparator接口來 實現。需要重寫compare(T o1,T o2)方法。
  • 利用int compare(T o1,T o2)方法,比較o1和o2的大小:如果方法返回正整數,則表 示o1大於o2;如果返回0,表示相等;返回負整數,表示o1小於o2。
  • 要實現定製排序,需要將實現Comparator接口的實例作爲形參傳遞給TreeSet的構 造器。
  • 此時,仍然只能向TreeSet中添加類型相同的對象。否則發生ClassCastException異 常。
  • 使用定製排序判斷兩個元素相等的標準是:通過Comparator比較兩個元素返回了0

Map接口

  • Map與Collection並列存在。用於保存具有映射關係的數據:key-value
  • Map 中的 key 和 value 都可以是任何引用類型的數據
  • Map 中的 key 用Set來存放,不允許重複,即同一個 Map 對象所對應 的類,須重寫hashCode()和equals()方法  常用String類作爲Map的“鍵”
  • key 和 value 之間存在單向一對一關係,即通過指定的 key 總能找到 唯一的、確定的 value
  • Map接口的常用實現類:HashMap、TreeMap、LinkedHashMap和 Properties。其中,HashMap是 Map 接口使用頻率最高的實現類

Map接口:常用方法:(點擊這裏)

Map實現類之一:HashMap

  • HashMap是 Map 接口使用頻率最高的實現類。
  • 允許使用null鍵和null值,與HashSet一樣,不保證映射的順序。
  • 所有的key構成的集合是Set:無序的、不可重複的。所以,key所在的類要重寫: equals()和hashCode()
  • 所有的value構成的集合是Collection:無序的、可以重複的。所以,value所在的類 要重寫:equals()
  • 一個key-value構成一個entry
  • 所有的entry構成的集合是Set:無序的、不可重複的
  • HashMap 判斷兩個 key 相等的標準是:兩個 key 通過 equals() 方法返回 true, hashCode 值也相等。
  • HashMap 判斷兩個 value相等的標準是:兩個 value 通過 equals() 方法返回 true
  • HashMap是非同步的(線程不安全),想要線程同步的HashMap可以用HashTable或ConcurrentHashMap。
    在這裏插入圖片描述
  • HashMap的內部存儲結構其實是數組和鏈表的結合。當實例化一個HashMap時, 系統會創建一個長度爲Capacity的Entry數組,這個長度在哈希表中被稱爲容量 (Capacity),在這個數組中可以存放元素的位置我們稱之爲“桶”(bucket),每個 bucket都有自己的索引,系統可以根據索引快速的查找bucket中的元素。
  • 每個bucket中存儲一個元素,即一個Entry對象,但每一個Entry對象可以帶一個引 用變量,用於指向下一個元素,因此,在一個桶中,就有可能生成一個Entry鏈。 而且新添加的元素作爲鏈表的head。
  • 添加元素的過程: 向HashMap中添加entry1(key,value),需要首先計算entry1中key的哈希值(根據 key所在類的hashCode()計算得到),此哈希值經過處理以後,得到在底層Entry[]數 組中要存儲的位置i。如果位置i上沒有元素,則entry1直接添加成功。如果位置i上 已經存在entry2(或還有鏈表存在的entry3,entry4),則需要通過循環的方法,依次 比較entry1中key和其他的entry。如果彼此hash值不同,則直接添加成功。如果 hash值不同,繼續比較二者是否equals。如果返回值爲true,則使用entry1的value 去替換equals爲true的entry的value。如果遍歷一遍以後,發現所有的equals返回都 爲false,則entry1仍可添加成功。entry1指向原有的entry元素。

Map實現類之二:LinkedHashMap

  • LinkedHashMap 是 HashMap 的子類
  • 在HashMap存儲結構的基礎上,使用了一對雙向鏈表來記錄添加
    元素的順序
    與LinkedHashSet類似,LinkedHashMap 可以維護 Map 的迭代 順序:迭代順序與 Key-Value 對的插入順序一

Map實現類之三:TreeMap

  • TreeMap存儲 Key-Value 對時,需要根據 key-value 對進行排序。 TreeMap 可以保證所有的 Key-Value 對處於有序狀態。
  • TreeSet底層使用紅黑樹結構存儲數據
  • TreeMap 的 Key 的排序:
    • 自然排序:TreeMap 的所有的 Key 必須實現 Comparable 接口,而且所有 的 Key 應該是同一個類的對象,否則將會拋出 ClasssCastException
    • 定製排序:創建 TreeMap 時,傳入一個 Comparator 對象,該對象負責對 TreeMap 中的所有 key 進行排序。此時不需要 Map 的 Key 實現 Comparable 接口
  • TreeMap判斷兩個key相等的標準:兩個key通過compareTo()方法或 者compare()方法返回0。

Map實現類之四:Hashtable

  • Hashtable是個古老的 Map 實現類,JDK1.0就提供了。不同於HashMap, Hashtable是線程安全的。
  • Hashtable實現原理和HashMap相同,功能相同。底層都使用哈希表結構,查詢 速度快,很多情況下可以互用。
  • 與HashMap不同,Hashtable 不允許使用 null 作爲 key 和 value
  • 與HashMap一樣,Hashtable 也不能保證其中 Key-Value 對的順序
  • Hashtable判斷兩個key相等、兩個value相等的標準,與HashMap一致

Map實現類之五:Properties

  • Properties 類是 Hashtable 的子類,該對象用於處理屬性文件
  • 由於屬性文件裏的 key、value 都是字符串類型,所以 Properties 裏的 key 和 value 都是字符串類型
  • 存取數據時,建議使用setProperty(String key,String value)方法和 getProperty(String key)方法
Properties pros = new Properties();
pros.load(new FileInputStream("jdbc.properties"));
String user = pros.getProperty("user");
System.out.println(user)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章