集合系列(一):集合框架概述

来源:https://www.cnblogs.com/chanshuyi/archive/2019/08/23/java_collection_01_summary.html
-Advertisement-
Play Games

集合系列(一):集合框架概述 Java 集合是 Java API 用得最頻繁的一類,掌握 Java 集合的原理以及繼承結構非常有必要。總的來說,Java 容器可以劃分為 4 個部分: List 集合 Set 集合 Queue 集合 Map 集合 除了上面 4 種集合之外,還有一個專門的工具類: 工具 ...


集合系列(一):集合框架概述

Java 集合是 Java API 用得最頻繁的一類,掌握 Java 集合的原理以及繼承結構非常有必要。總的來說,Java 容器可以劃分為 4 個部分:

  • List 集合
  • Set 集合
  • Queue 集合
  • Map 集合

除了上面 4 種集合之外,還有一個專門的工具類:

  • 工具類(Iterator 迭代器、Enumeration 枚舉類、Arrays 和 Collections)

在開始聊具體的集合體系之前,我想先介紹一下 Collection 框架的基本類結構。因為無論是 List 集合、Set 集合還是 Map 集合都以這個為基礎。

  • 首先,最頂層的是 Collection 介面。

可以看到 Collection 介面定義了最最基本的集合操作,例如:判斷集合大小、判斷集合是否為空等。List、Set、Queue 都繼承了該介面。

  • 接著,AbstractCollection 也繼承了 Collection 介面。

從這個類名可以看出,其是一個抽象類。AbstractCollection 對 Collection 介面中一些通用的方法做了實現。例如:判斷是否為空的方法、判斷是否包含某個元素的方法等。

通過繼承 AbstractCollection 介面,可以少寫許多不必要的代碼,這是代碼抽象設計最常用的思想。AbstractCollection 是最為基礎的類,其他所有集合的實現都繼承了這個抽象類。

List 集合

List 集合存儲的是有序的數據集合,其數據結構特點是:讀取快,修改慢,適合於讀取多、寫入修改少的場景。List 集合的類繼承結構如下:

我們可以看到除了 Collection 和 AbstractCollection 之外,我們還有 List 介面和 AbstractList 抽象類。其中 List 介面是 List 集合的最上層抽象,其繼承了 Collection 介面,表示其實一個集合。而 AbstractList 則是 List 集合的抽象實現,實現了許多公用的操作。

整個 List 集合的實現可以分為紅、黃、綠三大塊。其中紅色部分是 List 集合的列表實現,綠色部分是 List 結合的鏈表實現,而 黃色部分則是 List 集合列表實現的線程安全版本。

列表實現

ArrayList 類是很常用的 List 實現,其底層是用數組實現的。其讀取元素的時間複雜度是 O(1),修改寫入元素的時間複雜度是 O(N)。我們將會在下麵的章節中詳細介紹,這裡不做深入。

列表安全實現

Vector 類也是很常用的 List 實現,其數據結構與 ArrayList 非常類似。但其與 ArrayList 的一個最大的不同是:Vector 是線程安全的,而 ArrayList 則不是線程安全的。

Stack 類則是在 Vector 的基礎上,又實現了一個雙向隊列。所以其除了是線程安全的之外,其還是一個先進後出的 List 實現。

最後我們總結一下,List 集合最為關鍵的幾個實現類是:

  • ArrayList:列表集合經典實現。
  • Vector:列表集合經典實現,線程安全,與 ArrayList 對應。
  • Stack:棧結構的經典實現,先進後出的數據結構。繼承了 Vector,線程安全。
  • LinkedList:鏈表結構的經典實現。

鏈表實現

LinkedList 是一個經典的鏈表實現。LinkedList 繼承了 AbstractSequentialList 抽象類。AbstractSequentialList 抽象類從字面上理解是抽象連續列表。這裡的重點是
sequential 這個詞,表示其數據結構是連續的(鏈表)。從其源碼註釋也可以看出這個意思。

This class provides a skeletal implementation of the List interface to minimize the effort required to implement this interface backed by a "sequential access" data store (such as a linked list).
(意譯)如果你想要實現一個連續存儲(鏈表)的 List,那麼這個抽象類可以讓你減少不少工足量。

其實從命名就可以看出,AbstractSequentialList 其實是連續列表(鏈表)的一個抽象實現。AbstractSequentialList 抽象類做了許多工作,使得後續的鏈表實現更加簡單。從 AbstractSequentialList 的註釋可以看到,如果要實現一個鏈表,那麼只需要實現 listIterator 方法和 size 方法就可以了。

Set 集合

Set 集合中存儲的元素是不重覆的,但是其存儲順序是無序的。下麵是 Set 集合的類繼承結構圖:

與 List 集合類似,都是一個 Set 介面繼承了 Collection 介面。一個 AbstractSet 抽象類實現了 Set 介面、繼承了 AbstractCollection 抽象類。這部分完全和 List 相同。

Set 集合的實現可以分為兩大塊,一塊是 Set 集合的有序實現(紅色部分),另一塊是 Set 集合的哈希實現(黃色部分)。

有序實現(TreeSet)

  • SortedSet 介面繼承了 Set 介面,TreeSet 實現了 SortedSet。

我們知道 Set 集合中的元素是無序的,而 SortedSet 介面則是定義了有序 Set 集合的介面。而 TreeSet 則是 SortedSet 的具體實現。

哈希實現(HashSet、LinkedHashSet)

HashSet 是 Set 介面的經典哈希實現。但 Set 集合中的元素是無序的,為了維護 Set 集合的插入順序,人們創造出了 LinkedHashSet。LinkedHashSet 在 HashSet 的基礎上是用鏈表維護元素的插入順序。

到這裡我們總結一下 Set 集合的所有實現:

  • TreeSet:Set 集合的有序實現。
  • HashSet:Set 集合的哈希實現。
  • LinkedHashSet:Set 集合的哈希實現,維護了元素插入順序。

Queue 集合

隊列是一個特殊的線性表,其數據結構特點是先進先出。Queue 類結構體系如下圖所示:

首先,Queue 介面繼承了 Collection 介面。Queue 介面在擁有基本集合操作的基礎上,定義了隊列這種數據結構的基本操作。可以看到 offer、poll 等方法都是隊列獨有的操作。

接著,AbstractQueue 是對 Queue 介面的抽象實現。針對隊列這種數據結構,其添加、刪除元素的動作都不一樣。在 AbstractQueue 抽象類里將隊列的基本操作都實現了一遍。例如 AbstractQueue 中的 add 方法就和 AbstractList 中的 add 方法有著不同的實現。

如上圖所示,Queue 的類結構整體可以分為黃色、紅色兩個部分。紅色部分是 Queue 介面的有序實現,有 PriorityQueue 這個實現類。黃色部分是 Deque(雙向隊列)的實現,有 LinkedList 和 ArrayDeque 兩個實現類。

有序實現

PriorityQueue 是 AbstractQueue 抽象類的具體實現。

PriorityQueue 表示優先順序隊列,其按照隊列元素的大小進行重新排序。當調用 peek() 或 pool() 方法取出隊列中頭部的元素時,並不是取出最先進入隊列的元素,而是取出隊列的最小元素。

雙向實現

  • 首先,我們會看到 Deque 介面。

Deque(double ended queue)是雙向隊列的意思,它能在頭部或尾部進行元素操作。

  • 最後,我們看到 LinkedList 和 ArrayDeque 都是 Deque 介面的具體實現。

LinkedList 我們之前說過了,是一個鏈表,但它還是一個雙向隊列。因此 LinkedList 具有 List 和 Queue 的雙重特性。ArrayDeque 則是一個雙向迴圈隊列,其底層是用數組實現。更多內容,我們將在隊列章節講解。

最後我們總結 Queue 體系的幾個常見實現類:

  • PriorityQueue:優先順序隊列
  • LinkedList:雙向隊列實現
  • ArrayDeque:雙向迴圈隊列實現

Map 集合

Map 集合與 List、Set、Queue 有較大不同,其實類似於 key/value 的數據結構。

  • 首先,Map 介面是最頂層的介面。

與 List、Set、Queue 類似,Map 介面定義的是哈希表數據結構的操作。例如我們常用的 put、get、keySet 等。

  • 接著,有 AbstractMap 抽象類。

和 List 等類似,AbstractMap 是 Map 介面的抽象實現。如上圖所示,Map 集合的整個類結構可以分為紅、黃、綠三塊。

哈希實現

紅色部分可以看成是 Map 的哈希實現。

  • AbstractMap 有具體的實現類 HashMap。

HashMap 是 AbstractMap 基於哈希演算法的具體實現。

  • 接著,LinkedHashMap 和 WeakedHashMap 繼承了 HashMap。

LinkedHashMap 是 HashMap 的進一步實現,其用鏈表保存了插入 HashMap 中的元素順序。WeakedHashMap 是 HashMap 的進一步實現,與 HashMap不同的是:WeakedHashMap 中的引用是弱引用,如果太久沒用,則會被自動回收。

有序實現

黃色部分可以看成是 Map 集合的有序實現。

  • 首先,SortedMap 介面繼承了 Map 介面。

與 Set 一樣,Map 中的元素是沒有順序的,SortedMap 就是有序 Map 的介面定義。

  • 接著,NavigableMap 繼承了 SortedMap 介面。

NavigableMap 介面定義了一些查找邏輯,方便後續實現。

  • 最後,TreeMap 則是 NavigableMap 介面的具體實現。

其實 TreeMap 是基於紅黑樹的 Map 實現。

看到了這裡,Map 整個類結構看完了一半。而另外一半則是以 Dictionary 為主的實現(綠色部分)。但實際上 Dictionary 是老舊的 Map 實現,現在已經廢棄了。我們從源碼的註釋中可以看到相關的提示。

NOTE: This class is obsolete(廢棄的).  New implementations should implement the Map interface, rather than extending this class.
這個類已經被廢棄,新的實現應該實現 Map 介面,而不是擴展這個類。

所以針對於 Dictionary 的實現,我們並不打算深入講解。

到這裡我們總結一下 Map 集合的所有實現類:

  • HashMap:Map 集合的經典哈希實現。
  • LinkedHashMap:在 HashMap 的基礎上,增加了對插入元素的鏈表維護。
  • WeakedHashMap:在 HashMap 的基礎上,使強引用變為弱引用。
  • TreeMap:Map 集合的有序實現。

工具類

集合的工具類有:Iterator 迭代器、ListIterator 迭代器、Enumeration 枚舉類、Arrays 和 Collections 類。

Iterator 迭代器

Iterator 迭代器是一個用來遍歷並選擇序列中的對象。Java 的 Iterator 只能單向移動。可以看到在 ArrayList、WeakHashMap 等集合類都實現了該介面,從而實現不同類型集合的遍歷。

ListIterator 迭代器

ListIterator 繼承了 Iterator 介面,所以其有更強大的功能,即它能夠實現雙向移動。但從其名字也可以看出,其只能適用於 List 集合的遍歷。

Enumeration 枚舉類

它是 JDK 1.0引入的介面。作用和Iterator一樣,也是遍歷集合。但是Enumeration的功能要比Iterator少。Enumeration只能在Hashtable, Vector, Stack中使用。這種傳統介面已被迭代器取代,雖然 Enumeration 還未被遺棄,但在代碼中已經被很少使用了。

官方也在文檔中推薦使用 Iterator 介面來替代 Enumeration 介面。

Arrays

Java.util.Arrays類能方便地操作數組,它提供的所有方法都是靜態的。

Collections

java.util.Collections 是一個包含各種有關集合操作的靜態多態方法的工具類,服務於 Java 的 Collection 框架。

總結

我們花費了大量的篇幅講解了 List 集合、Set 集合、Map 集合、Queue 集合以及 Iterator 等工具類。我們對這集合的類結構進行了詳細的解析,從而更加瞭解他們之間的關係。

有時候我們會想,瞭解這麼多有啥用呢。我有個朋友只用了常見的 ArrayList、HashMap 就可以了啊。對於這個問題,我想分享幾個收穫。

第一,讓你更加熟悉類之間的差異。 如果我們只會用一兩個類,那麼我們就不知道在什麼時候用什麼類。例如:什麼時候用 HashMap,什麼時候用 Hashtable?Iterator 介面有什麼作用?JDK源碼的命名有什麼特點?

第二,方便對源碼進行擴展。 當我們深入研究了集合的實現之後,我們知道了原來 List 介面就是 List 這種數據類型的定義,而 AbstractList 是 List 的抽象實現。那麼如果我們要實現一個自定義的 List 結構,那麼我們就可以直接繼承 AbstractList 類,從而達到快速實現的目的。但如果你沒有深入研究呢?你或許只能從頭寫起,這樣得浪費多大的精力啊。你學會了這種方式,那麼對於你擴展 Spring 源碼也是有很好的幫助的。

在接下來的文章里,我們將深入介紹每一個集合的具體實現。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • jQuery是一個Javascript庫,它支持鏈式操作方式,即對發生在同一個JQuery對象上的一組動作,可以直接接連寫無需要重覆獲取對象。這一特點使得JQuery的代碼無比優雅,而且有強大的選擇器,出色的DOM操作,可靠的事件處理機制,完善的Ajax,關鍵是有出色的瀏覽器相容性,開發項目時可以不 ...
  • 1. ...
  • 這次分享我們就來談談單例模式的使用,其實在本公眾號設計模式的第一篇分享就是單例模式,為什麼又要討論單例模式了?主要是那篇文章談的比較淺,只對單例模式的主要思想做了一個分享,這篇文章會從多個方面去分享單例模式的使用,下麵進入正題。 使用Java做程式的小伙伴都知道單例,尤其是使用spring框架做項目 ...
  • 本文將介紹微服務架構和相關的組件,介紹他們是什麼以及為什麼要使用微服務架構和這些組件。本文側重於簡明地表達微服務架構的全局圖景,因此不會涉及具體如何使用組件等細節。 為了防止不提供原網址的轉載,特在這裡加上原文鏈接: "https://www.cnblogs.com/skabyy/p/1139657 ...
  • 代碼參考:https://github.com/HCJ shadow/Zuul Gateway Cluster Nginx Zuul的路由轉發功能 前期準備 搭建Eureka服務註冊中心 服務提供者msc provider 5001【提供一個hello請求做測試】 創建gateway 7001 p ...
  • 一、複習 1.標識符(自己定義的,下劃線、美元符號) 2.駝峰命名(變數名,方法名首字母小寫) 3.關鍵字(就是固定的那幾個) 4.字面值(數據、有類型、八種基本類型從小到大,byte\char=short\int\long\float\double\boolean 5.成員變數(初始化在方法外且不 ...
  • 23:59 2019/8/23 成員變數: 對象的成員變數,或者普通成員變數; 類的成員變數,或者靜態成員變數 下麵是source code和.class->.java(反編譯後)的source code ...
  • 功能需求:在前端頁面中,for迴圈id會構不成連續的順序號,所以要找到一種偽列的方式來根據數據量定義序號 因此就用到了在前端頁面中的一個欄位 forloop.counter,完美解決 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...