Java集合框架面試題

来源:https://www.cnblogs.com/aishangJava/archive/2018/11/22/10004341.html
-Advertisement-
Play Games

Arraylist 與 LinkedList 異同 1. 是否保證線程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保證線程安全; 2. 底層數據結構: Arraylist 底層使用的是Object數組;LinkedList 底層使用的是雙向迴圈鏈表數據結構; 3. 插 ...


Arraylist 與 LinkedList 異同

  • 1. 是否保證線程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保證線程安全;
  • 2. 底層數據結構: Arraylist 底層使用的是Object數組;LinkedList 底層使用的是雙向迴圈鏈表數據結構;
  • 3. 插入和刪除是否受元素位置的影響:ArrayList 採用數組存儲,所以插入和刪除元素的時間複雜度受元素位置的影響。 比如:執行add(E e)方法的時候, ArrayList 會預設在將指定的元素追加到此列表的末尾,這種情況時間複雜度就是O(1)。但是如果要在指定位置 i 插入和刪除元素的話(add(int index, E element))時間複雜度就為 O(n-i)。因為在進行上述操作的時候集合中第 i 和第 i 個元素之後的(n-i)個元素都要執行向後位/向前移一位的操作。 ② LinkedList 採用鏈表存儲,所以插入,刪除元素時間複雜度不受元素位置的影響,都是近似 O(1)而數組為近似 O(n)。
  • 4. 是否支持快速隨機訪問: LinkedList 不支持高效的隨機元素訪問,而ArrayList 實現了RandmoAccess 介面,所以有隨機訪問功能。快速隨機訪問就是通過元素的序號快速獲取元素對象(對應於get(int index)方法)。
  • 5. 記憶體空間占用: ArrayList的空 間浪費主要體現在在list列表的結尾會預留一定的容量空間,而LinkedList的空間花費則體現在它的每一個元素都需要消耗比ArrayList更多的空間(因為要存放直接後繼和直接前驅以及數據)。

補充:數據結構基礎之雙向鏈表

雙向鏈表也叫雙鏈表,是鏈表的一種,它的每個數據結點中都有兩個指針,分別指向直接後繼和直接前驅。所以,從雙向鏈表中的任意一個結點開始,都可以很方便地訪問它的前驅結點和後繼結點。一般我們都構造雙向迴圈鏈表,如下圖所示,同時下圖也是LinkedList 底層使用的是雙向迴圈鏈表數據結構。

 

 

 

ArrayList 與 Vector 區別

Vector類的所有方法都是同步的。可以由兩個線程安全地訪問一個Vector對象、但是一個線程訪問Vector的話代碼要在同步操作上耗費大量的時間。

Arraylist不是同步的,所以在不需要保證線程安全時時建議使用Arraylist。

HashMap的底層實現

JDK1.8之前

JDK1.8 之前 HashMap 由 數組+鏈表 組成的(“鏈表散列” 即數組和鏈表的結合體),數組是 HashMap 的主體,鏈表則是主要為瞭解決哈希衝突而存在的(HashMap 採用 “拉鏈法也就是鏈地址法” 解決衝突),如果定位到的數組位置不含鏈表(當前 entry 的 next 指向 null ),那麼對於查找,添加等操作很快,僅需一次定址即可;如果定位到的數組包含鏈表,對於添加操作,其時間複雜度依然為 O(1),因為最新的 Entry 會插入鏈表頭部,急需要簡單改變引用鏈即可,而對於查找操作來講,此時就需要遍歷鏈表,然後通過 key 對象的 equals 方法逐一比對查找.

所謂 “拉鏈法” 就是將鏈表和數組相結合。也就是說創建一個鏈表數組,數組中每一格就是一個鏈表。若遇到哈希衝突,則將衝突的值加到鏈表中即可。

 

jdk1.8之前的內部結構

 

 

JDK1.8之後

相比於之前的版本, JDK1.8之後在解決哈希衝突時有了較大的變化,當鏈表長度大於閾值(預設為8)時,將鏈表轉化為紅黑樹,以減少搜索時間。

 

JDK1.8之後的HashMap底層數據結構

 

 

TreeMap、TreeSet以及JDK1.8之後的HashMap底層都用到了紅黑樹。紅黑樹就是為瞭解決二叉查找樹的缺陷,因為二叉查找樹在某些情況下會退化成一個線性結構。

推薦閱讀:

HashMap 和 Hashtable 的區別

  1. 線程是否安全: HashMap 是非線程安全的,HashTable 是線程安全的;HashTable 內部的方法基本都經過 synchronized 修飾。(如果你要保證線程安全的話就使用 ConcurrentHashMap 吧!);
  2. 效率: 因為線程安全的問題,HashMap 要比 HashTable 效率高一點。另外,HashTable 基本被淘汰,不要在代碼中使用它;
  3. 對Null key 和Null value的支持: HashMap 中,null 可以作為鍵,這樣的鍵只有一個,可以有一個或多個鍵所對應的值為 null。。但是在 HashTable 中 put 進的鍵值只要有一個 null,直接拋出 NullPointerException。
  4. 初始容量大小和每次擴充容量大小的不同 : ①創建時如果不指定容量初始值,Hashtable 預設的初始大小為11,之後每次擴充,容量變為原來的2n+1。HashMap 預設的初始化大小為16。之後每次擴充,容量變為原來的2倍。②創建時如果給定了容量初始值,那麼 Hashtable 會直接使用你給定的大小,而 HashMap 會將其擴充為2的冪次方大小。也就是說 HashMap 總是使用2的冪作為哈希表的大小,後面會介紹到為什麼是2的冪次方。
  5. 底層數據結構: JDK1.8 以後的 HashMap 在解決哈希衝突時有了較大的變化,當鏈表長度大於閾值(預設為8)時,將鏈表轉化為紅黑樹,以減少搜索時間。Hashtable 沒有這樣的機制。

HashMap 的長度為什麼是2的冪次方

為了能讓 HashMap 存取高效,儘量較少碰撞,也就是要儘量把數據分配均勻,每個鏈表/紅黑樹長度大致相同。這個實現就是把數據存到哪個鏈表/紅黑樹中的演算法。

這個演算法應該如何設計呢?

我們首先可能會想到採用%取餘的操作來實現。但是,重點來了:“取餘(%)操作中如果除數是2的冪次則等價於與其除數減一的與(&)操作(也就是說 hash%length==hash&(length-1)的前提是 length 是2的 n 次方;)。” 並且 採用二進位位操作 &,相對於%能夠提高運算效率,這就解釋了 HashMap 的長度為什麼是2的冪次方。

HashSet 和 HashMap 區別

 

HashSet 和 HashMap 區別

 

 

ConcurrentHashMap 和 Hashtable 的區別

ConcurrentHashMap 和 Hashtable 的區別主要體現在實現線程安全的方式上不同。

  • 底層數據結構: JDK1.7的 ConcurrentHashMap 底層採用 分段的數組+鏈表 實現,JDK1.8 採用的數據結構跟HashMap1.8的結構一樣,數組+鏈表/紅黑二叉樹。Hashtable 和 JDK1.8 之前的 HashMap 的底層數據結構類似都是採用 數組+鏈表 的形式,數組是 HashMap 的主體,鏈表則是主要為瞭解決哈希衝突而存在的;
  • 實現線程安全的方式(重要):在JDK1.7的時候,ConcurrentHashMap(分段鎖) 對整個桶數組進行了分割分段(Segment),每一把鎖只鎖容器其中一部分數據,多線程訪問容器里不同數據段的數據,就不會存在鎖競爭,提高併發訪問率。(預設分配16個Segment,比Hashtable效率提高16倍。) 到了 JDK1.8 的時候已經摒棄了Segment的概念,而是直接用 Node 數組+鏈表+紅黑樹的數據結構來實現,併發控制使用 synchronized 和 CAS 來操作。(JDK1.6以後 對 synchronized鎖做了很多優化) 整個看起來就像是優化過且線程安全的 HashMap,雖然在JDK1.8中還能看到 Segment 的數據結構,但是已經簡化了屬性,只是為了相容舊版本;② Hashtable(同一把鎖) :使用 synchronized 來保證線程安全,效率非常低下。當一個線程訪問同步方法時,其他線程也訪問同步方法,可能會進入阻塞或輪詢狀態,如使用 put 添加元素,另一個線程不能使用 put 添加元素,也不能使用 get,競爭會越來越激烈效率越低。

兩者的對比圖:

圖片來源:www.cnblogs.com/chengxiao/p…

HashTable:

 

 

JDK1.7的ConcurrentHashMap:

 

JDK1.8的ConcurrentHashMap(TreeBin: 紅黑二叉樹節點 Node: 鏈表節點):

ConcurrentHashMap線程安全的具體實現方式/底層具體實現

JDK1.7(上面有示意圖)

首先將數據分為一段一段的存儲,然後給每一段數據配一把鎖,當一個線程占用鎖訪問其中一個段數據時,其他段的數據也能被其他線程訪問。

ConcurrentHashMap 是由 Segment 數組結構和 HahEntry 數組結構組成

Segment 實現了 ReentrantLock,所以 Segment 是一種可重入鎖,扮演鎖的角色。HashEntry 用於存儲鍵值對數據。

  1.   static class Segment<K,V> extends ReentrantLock implements Serializable {
  2.   }

一個 ConcurrentHashMap 里包含一個 Segment 數組。Segment 的結構和HashMap類似,是一種數組和鏈表結構,一個 Segment 包含一個 HashEntry 數組,每個 HashEntry 是一個鏈表結構的元素,每個 Segment 守護著一個HashEntry數組裡的元素,當對 HashEntry 數組的數據進行修改時,必須首先獲得對應的 Segment的鎖。

JDK1.8 (上面有示意圖)

ConcurrentHashMap取消了Segment分段鎖,採用CAS和synchronized來保證併發安全。數據結構跟HashMap1.8的結構類似,數組+鏈表/紅黑二叉樹。

synchronized只鎖定當前鏈表或紅黑二叉樹的首節點,這樣只要hash不衝突,就不會產生併發,效率又提升N倍。

集合框架底層數據結構總結

Collection

1. List

  • Arraylist: Object數組
  • Vector: Object數組
  • LinkedList: 雙向迴圈鏈表

2. Set

  • HashSet(無序,唯一): 基於 HashMap 實現的,底層採用 HashMap 來保存元素
  • LinkedHashSet: LinkedHashSet 繼承與 HashSet,並且其內部是通過 LinkedHashMap 來實現的。有點類似於我們之前說的LinkedHashMap 其內部是基於 Hashmap 實現一樣,不過還是有一點點區別的。
  • TreeSet(有序,唯一): 紅黑樹(自平衡的排序二叉樹。)

Map

  • HashMap: JDK1.8之前HashMap由數組+鏈表組成的,數組是HashMap的主體,鏈表則是主要為瞭解決哈希衝突而存在的(“拉鏈法”解決衝突).JDK1.8以後在解決哈希衝突時有了較大的變化,當鏈表長度大於閾值(預設為8)時,將鏈表轉化為紅黑樹,以減少搜索時間
  • LinkedHashMap: LinkedHashMap 繼承自 HashMap,所以它的底層仍然是基於拉鏈式散列結構即由數組和鏈表或紅黑樹組成。另外,LinkedHashMap 在上面結構的基礎上,增加了一條雙向鏈表,使得上面的結構可以保持鍵值對的插入順序。同時通過對鏈表進行相應的操作,實現了訪問順序相關邏輯。詳細可以查看:《LinkedHashMap 源碼詳細分析(JDK1.8)》
  • HashTable: 數組+鏈表組成的,數組是 HashMap 的主體,鏈表則是主要為瞭解決哈希衝突而存在的
  • TreeMap: 紅黑樹(自平衡的排序二叉樹)

推薦閱讀:


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

-Advertisement-
Play Games
更多相關文章
  • 原地址:https://www.cnblogs.com/hongten/p/hongten_java_sleep_wait.html ...
  • 1.網路通信協議 osi七層模型:按照分工不同把互聯網協議從邏輯上劃分了層級 socket層 2.理解socket: Socket是應用層與TCP/IP協議族通信的中間軟體抽象層,它是一組介面。在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket介面後面,對 ...
  • 正常情況下,新激活的goroutine的結束過程是不可控制的,唯一可以保證終止goroutine的行為是main goroutine的終止。也就是說,我們並不知道哪個goroutine什麼時候結束。 但很多情況下,我們正需要知道goroutine是否完成。這需要藉助sync包的WaitGroup來實 ...
  • 1.C/S架構 C/S架構:Client與Server ,中文意思:客戶端與伺服器端架構,這種架構也是從用戶層面(也可是物理層面)來劃分的。這裡客戶端一般指需先安裝再執行的應用程式,對操作系統依賴性較大;服務端即是這類程式對應的伺服器。 B/S架構:browser/server,瀏覽器端與伺服器端架 ...
  • worker pool簡介 worker pool其實就是線程池thread pool。對於go來說,直接使用的是goroutine而非線程,不過這裡仍然以線程來解釋線程池。 線上程池模型中, 有2個隊列一個池子:任務隊列、已完成任務隊列和線程池 。其中已完成任務隊列可能存在也可能不存在,依據實際需 ...
  • 資料庫事務的四大特性以及事務的隔離級別 本篇講訴資料庫中事務的四大特性(ACID),並且將會詳細地說明事務的隔離級別。 如果一個資料庫聲稱支持事務的操作,那麼該資料庫必須要具備以下四個特性: ⑴ 原子性(Atomicity) 原子性是指事務包含的所有操作要麼全部成功,要麼全部失敗回滾,這和前面兩篇博 ...
  • Python基礎知識(10):函數(Ⅱ) 一、全局變數和局部變數 局部變數:在函數內定義的變數,在函數內使用 全局變數:在函數外定義的變數,在程式任何地方都可以使用 1、全局變數與局部變數同名 這時函數內部只調用局部變數,如果要調用全局變數需要在函數內加一句“global 同名變數” 結果:1 2、 ...
  • 首先請看下麵的程式: 1. 註釋 2.對中文的支持 python2和python3不一樣,python3預設支持,python2 需要加上 3.變數 為了更充分的利用記憶體空間以及更有效率的管理記憶體,變數是有不同的類型的,如下所示 怎樣知道一個變數的類型呢? 在python中,只要定義了一個變數,而且 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...