Java集合框架詳解(全)

来源:https://www.cnblogs.com/bingyimeiling/archive/2019/01/14/10255037.html
-Advertisement-
Play Games

Java集合類主要由兩個根介面Collection和Map派生出來的,Collection派生出了三個子介面:List、Set、Queue(Java5新增的隊列),因此Java集合大致也可分成List、Set、Queue、Map四種介面體系,(註意:Map不是Collection的子介面)。 ...


一、Java集合框架概述

 

 

  集合可以看作是一種容器,用來存儲對象信息。所有集合類都位於java.util包下,但支持多線程的集合類位於java.util.concurrent包下。

  數組與集合的區別如下:

  1)數組長度不可變化而且無法保存具有映射關係的數據;集合類用於保存數量不確定的數據,以及保存具有映射關係的數據。

  2)數組元素既可以是基本類型的值,也可以是對象;集合只能保存對象。

  Java集合類主要由兩個根介面CollectionMap派生出來的,Collection派生出了三個子介面:List、Set、Queue(Java5新增的隊列),因此Java集合大致也可分成List、Set、Queue、Map四種介面體系,(註意:Map不是Collection的子介面)。

  其中List代表了有序可重覆集合,可直接根據元素的索引來訪問;Set代表無序不可重覆集合,只能根據元素本身來訪問;Queue是隊列集合;Map代表的是存儲key-value對的集合,可根據元素的key來訪問value。

  上圖中淡綠色背景覆蓋的是集合體系中常用的實現類,分別是ArrayList、LinkedList、ArrayQueue、HashSet、TreeSet、HashMap、TreeMap等實現類。

二、Java集合常見介面及實現類

1. Collection介面常見方法(來源於Java API)

2. Set集合

   Set集合與Collection的方法相同,由於Set集合不允許存儲相同的元素,所以如果把兩個相同元素添加到同一個Set集合,則添加操作失敗,新元素不會被加入,add()方法返回false。為了幫助理解,請看下麵代碼示例:

public class Test {

    public static void main(String[] args) {
        Set<String> set = new HashSet<String>();
        set.add("hello world");
        set.add("hello 冰湖一角");
        set.add("hello 冰湖一角");//添加不進去
        System.out.println("集合中元素個數:"+set.size());
        System.out.println("集合中元素為:"+set.toString());
    }
}

運行結果如下:

集合中元素個數:2
集合中元素為:[hello world, hello 冰湖一角]

分析:由於String類中重寫了hashCode()和equals()方法,用來比較指向的字元串對象所存儲的字元串是否相等。所以這裡的第二個"hello 冰湖一角"是加不進去的。

下麵著重介紹Set集合幾個常用實現類:

1)HashSet類

  HashSet是Set集合最常用實現類,是其經典實現。HashSet是按照hash演算法來存儲元素的,因此具有很好的存取和查找性能。

  HashSet具有如下特點:

  ♦ 不能保證元素的順序。

  ♦ HashSet不是線程同步的,如果多線程操作HashSet集合,則應通過代碼來保證其同步。

  ♦ 集合元素值可以是null。

  HashSet存儲原理如下:

  當向HashSet集合存儲一個元素時,HashSet會調用該對象的hashCode()方法得到其hashCode值,然後根據hashCode值決定該對象的存儲位置。HashSet集合判斷兩個元素相等的標準是(1)兩個對象通過equals()方法比較返回true;(2)兩個對象的hashCode()方法返回值相等。因此,如果(1)和(2)有一個不滿足條件,則認為這兩個對象不相等,可以添加成功。如果兩個對象的hashCode()方法返回值相等,但是兩個對象通過equals()方法比較返回false,HashSet會以鏈式結構將兩個對象保存在同一位置,這將導致性能下降,因此在編碼時應避免出現這種情況。

  HashSet查找原理如下:

  基於HashSet以上的存儲原理,在查找元素時,HashSet先計算元素的HashCode值(也就是調用對象的hashCode方法的返回值),然後直接到hashCode值對應的位置去取出元素即可,這就是HashSet速度很快的原因。

   重寫hashCode()方法的基本原則如下:

   ♦ 在程式運行過程中,同一個對象的hashCode()方法返回值應相同。

  ♦ 當兩個對象通過equals()方法比較返回true時,這兩個對象的hashCode()方法返回值應該相等。

  ♦ 對象中用作equals()方法比較標準的實例變數,都應該用於計算hashCode值。

 2)LinkedHashSet類

   LinkedHashSet是HashSet的一個子類,具有HashSet的特性,也是根據元素的hashCode值來決定元素的存儲位置。但它使用鏈表維護元素的次序,元素的順序與添加順序一致。由於LinkedHashSet需要維護元素的插入順序,因此性能略低於HashSet,但在迭代訪問Set里的全部元素時由很好的性能。

 3)TreeSet類

  TreeSet時SortedSet介面的實現類,TreeSet可以保證元素處於排序狀態,它採用紅黑樹的數據結構來存儲集合元素。TreeSet支持兩種排序方法:自然排序和定製排序,預設採用自然排序。

  ♦ 自然排序

  TreeSet會調用集合元素的compareTo(Object obj)方法來比較元素的大小關係,然後將元素按照升序排列,這就是自然排序。如果試圖將一個對象添加到TreeSet集合中,則該對象必須實現Comparable介面,否則會拋出異常。當一個對象調用方法與另一個對象比較時,例如obj1.compareTo(obj2),如果該方法返回0,則兩個對象相等;如果返回一個正數,則obj1大於obj2;如果返回一個負數,則obj1小於obj2。

  Java常用類中已經實現了Comparable介面的類有以下幾個:

  ♦ BigDecimal、BigDecimal以及所有數值型對應的包裝類:按照它們對應的數值大小進行比較。

  ♦ Charchter:按照字元的unicode值進行比較。

  ♦ Boolean:true對應的包裝類實例大於false對應的包裝類實例。

  ♦ String:按照字元串中的字元的unicode值進行比較。

  ♦ Date、Time:後面的時間、日期比前面的時間、日期大。

  對於TreeSet集合而言,它判斷兩個對象是否相等的標準是:兩個對象通過compareTo(Object obj)方法比較是否返回0,如果返回0則相等。

   ♦ 定製排序

  想要實現定製排序,需要在創建TreeSet集合對象時,提供一個Comparator對象與該TreeSet集合關聯,由Comparator對象負責集合元素的排序邏輯。

  綜上:自然排序實現的是Comparable介面,定製排序實現的是Comparator介面。(具體代碼實現會在後續章節中講解)

 4)EnumSet類

  EnumSet是一個專為枚舉類設計的集合類,不允許添加null值。EnumSet的集合元素也是有序的,它以枚舉值在Enum類內的定義順序來決定集合元素的順序。

5)各Set實現類的性能分析

  HashSet的性能比TreeSet的性能好(特別是添加,查詢元素時),因為TreeSet需要額外的紅黑樹演算法維護元素的次序,如果需要一個保持排序的Set時才用TreeSet,否則應該使用HashSet。

  LinkedHashSet是HashSet的子類,由於需要鏈表維護元素的順序,所以插入和刪除操作比HashSet要慢,但遍歷比HashSet快。

  EnumSet是所有Set實現類中性能最好的,但它只能 保存同一個枚舉類的枚舉值作為集合元素。

  以上幾個Set實現類都是線程不安全的,如果多線程訪問,必須手動保證集合的同步性,這在後面的章節中會講到。

3. List集合

  List集合代表一個有序、可重覆集合,集合中每個元素都有其對應的順序索引。List集合預設按照元素的添加順序設置元素的索引,可以通過索引(類似數組的下標)來訪問指定位置的集合元素。

  實現List介面的集合主要有:ArrayList、LinkedList、Vector、Stack。

1)ArrayList

      ArrayList是一個動態數組,也是我們最常用的集合,是List類的典型實現。它允許任何符合規則的元素插入甚至包括null。每一個ArrayList都有一個初始容量(10),該容量代表了數組的大小。隨著容器中的元素不斷增加,容器的大小也會隨著增加。在每次向容器中增加元素的同時都會進行容量檢查,當快溢出時,就會進行擴容操作。所以如果我們明確所插入元素的多少,最好指定一個初始容量值,避免過多的進行擴容操作而浪費時間、效率。

      ArrayList擅長於隨機訪問。同時ArrayList是非同步的。

2)LinkedList

     LinkedList是List介面的另一個實現,除了可以根據索引訪問集合元素外,LinkedList還實現了Deque介面,可以當作雙端隊列來使用,也就是說,既可以當作“棧”使用,又可以當作隊列使用。

  LinkedList的實現機制與ArrayList的實現機制完全不同,ArrayLiat內部以數組的形式保存集合的元素,所以隨機訪問集合元素有較好的性能;LinkedList內部以鏈表的形式保存集合中的元素,所以隨機訪問集合中的元素性能較差,但在插入刪除元素時有較好的性能。

3)Vector

      與ArrayList相似,但是Vector是同步的。所以說Vector是線程安全的動態數組。它的操作與ArrayList幾乎一樣。

4)Stack

     Stack繼承自Vector,實現一個後進先出的堆棧。Stack提供5個額外的方法使得Vector得以被當作堆棧使用。基本的push和pop 方法,還有peek方法得到棧頂的元素,empty方法測試堆棧是否為空,search方法檢測一個元素在堆棧中的位置。Stack剛創建後是空棧。

5)Iterator介面和ListIterator介面

  Iterator是一個介面,它是集合的迭代器。集合可以通過Iterator去遍歷集合中的元素。Iterator提供的API介面如下:

  ♦ boolean hasNext():判斷集合里是否存在下一個元素。如果有,hasNext()方法返回 true。
  ♦ Object next():返回集合里下一個元素。
  ♦ void remove():刪除集合里上一次next方法返回的元素。

  ListIterator介面繼承Iterator介面,提供了專門操作List的方法。ListIterator介面在Iterator介面的基礎上增加了以下幾個方法:

  ♦ boolean hasPrevious():判斷集合里是否存在上一個元素。如果有,該方法返回 true。
  ♦ Object previous():返回集合里上一個元素。
  ♦ void add(Object o):在指定位置插入一個元素。

  以上兩個介面相比較,不難發現,ListIterator增加了向前迭代的功能(Iterator只能向後迭代),ListIterator還可以通過add()方法向List集合中添加元素(Iterator只能刪除元素)。

4. Map集合

  Map介面採用鍵值對Map<K,V>的存儲方式,保存具有映射關係的數據,因此,Map集合里保存兩組值,一組值用於保存Map里的key,另外一組值用於保存Map里的value,key和value可以是任意引用類型的數據。key值不允許重覆,可以為null。如果添加key-value對時Map中已經有重覆的key,則新添加的value會覆蓋該key原來對應的value。常用實現類有HashMap、LinkedHashMap、TreeMap等。

  Map常見方法(來源於API)如下:

 1)HashMap與Hashtable

  HashMap與Hashtable是Map介面的兩個典型實現,它們之間的關係完全類似於ArrayList與Vertor。HashTable是一個古老的Map實現類,它提供的方法比較繁瑣,目前基本不用了,HashMap與Hashtable主要存在以下兩個典型區別:

  ♦ HashMap是線程不安全,HashTable是線程安全的。

  ♦ HashMap可以使用null值最為key或value;Hashtable不允許使用null值作為key和value,如果把null放進HashTable中,將會發生空指針異常。

  為了成功的在HashMap和Hashtable中存儲和獲取對象,用作key的對象必須實現hashCode()方法和equals()方法。

  HashMap工作原理如下:

  HashMap基於hashing原理,通過put()和get()方法存儲和獲取對象。當我們將鍵值對傳遞給put()方法時,它調用建對象的hashCode()方法來計算hashCode值,然後找到bucket位置來儲存值對象。當獲取對象時,通過建對象的equals()方法找到正確的鍵值對,然後返回對象。HashMap使用鏈表來解決碰撞問題,當發生碰撞了,對象將會存儲在鏈表的下一個節點中。

2)LinkedHashMap實現類

  LinkedHashMap使用雙向鏈表來維護key-value對的次序(其實只需要考慮key的次序即可),該鏈表負責維護Map的迭代順序,與插入順序一致,因此性能比HashMap低,但在迭代訪問Map里的全部元素時有較好的性能。

3)Properties

  Properties類時Hashtable類的子類,它相當於一個key、value都是String類型的Map,主要用於讀取配置文件。

4)TreeMap實現類

  TreeMap是SortedMap的實現類,是一個紅黑樹的數據結構,每個key-value對作為紅黑樹的一個節點。TreeMap存儲key-value對時,需要根據key對節點進行排序。TreeMap也有兩種排序方式:

  ♦ 自然排序:TreeMap的所有key必須實現Comparable介面,而且所有的key應該是同一個類的對象,否則會拋出ClassCastException。

  ♦ 定製排序:創建TreeMap時,傳入一個Comparator對象,該對象負責對TreeMap中的所有key進行排序。

5)各Map實現類的性能分析

  ♦ HashMap通常比Hashtable(古老的線程安全的集合)要快

  ♦ TreeMap通常比HashMap、Hashtable要慢,因為TreeMap底層採用紅黑樹來管理key-value。

  ♦ LinkedHashMap比HashMap慢一點,因為它需要維護鏈表來爆出key-value的插入順序。  

 

如需轉載,請註明作者(冰湖一角)和鏈接https://www.cnblogs.com/bingyimeiling/p/10255037.html

 

歡迎關註微信公眾號【Java典籍】,收看更多Java技術乾貨!

   ▼微信掃一掃下圖↓↓↓二維碼關註

 

 


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

-Advertisement-
Play Games
更多相關文章
  • 1.js得到規範的時間格式函數 Date.prototype.format = function(fmt) { var o = { "M+" : this.getMonth()+1, //月份 "d+" : this.getDate(), //日 "h+" : this.getHours(), // ...
  • flex屬性: flex屬性是flex-grow, flex-shrink 和 flex-basis的簡寫,預設值為0 1 auto。後兩個屬性可選。 該屬性有兩個快捷值:auto (1 1 auto) 和 none (0 0 auto)。 下麵來看看使用項目屬性flex的兩個示例: 一、 CSS: ...
  • 源碼:https://pan.baidu.com/s/1R12MwZYs0OJw3OWKsc8WNw 樣本:http://js.zhuamimi.cn/shizhong/ 我的百度經驗:https://jingyan.baidu.com/article/1974b28935a46bf4b1f774a ...
  • (三)功能開發 接上文,我們現在開始編寫Javascript代碼,前文我們主文件已經引入了js文件,只需在js文件中編寫代碼。 1.播放音頻; 怎樣才能讓頁面播放音頻呢?這需要“audio”標簽,但是我們不是在頁面總插入改標簽,而是用JS實現,只需編寫如下代碼: 這裡面要在項目根目錄中添加mp3目錄 ...
  •    系統數據量達到一定程度後必將採用分庫分表的方式來提高系統性能,但傳統的分庫分表方式也必將帶來更高的開發複雜程度。新一代的NewSql及NoSql資料庫由於天生的分散式存儲基因,既保證了能夠橫向擴展,又可以避免較高的開發複雜程度。AppBoxFuture框 ...
  • 第一個問題:什麼是作用域? 第二個問題:作用域在上面情況下形成? 第三個問題:什麼是變數提升,作用域鏈? 第四個問題:“=”賦值運算 第五個問題:生成對象的有幾種方式? 第六個問題:面向對象的三大特點 第七個問題:原型鏈 第八個問題:prototype和__proto__的區別? 第九個問題:jso ...
  • 責任鏈模式為請求創建了一個接受者對象的鏈。這種模式給予請求的類型,對請求的發送者和接受者進行解耦。這種類型的設計模式屬於行為模式。在這種模式下,通常每個接收者都包含對另一個接收者的引用。如果一個對象不能處理該對象,那麼它會把相同的請求傳給下一個接收者,以此類推 ...
  • 解釋器模式 解釋器模式是類的行為模式。給定一個語言之後,解釋器模式可以定義出其文法的一種表示,並同時提供一個解釋器。客戶端可以使用這個解釋器來解釋這個語言中的句子。 意圖 給定一個語言,定義它的文法表示,並定義一個解釋器,這個解釋器使用該標識來解釋語言中的句子。 主要解決 對於一些固定文法構建一個解 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...