成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

這幾道Java集合框架面試題在面試中幾乎必問

bigdevil_s / 3586人閱讀

摘要:若遇到哈希沖突,則將沖突的值加到鏈表中即可。之后相比于之前的版本,之后在解決哈希沖突時(shí)有了較大的變化,當(dāng)鏈表長度大于閾值默認(rèn)為時(shí),將鏈表轉(zhuǎn)化為紅黑樹,以減少搜索時(shí)間。有序,唯一紅黑樹自平衡的排序二叉樹。

本文是“最最最常見Java面試題總結(jié)”系列第三周的文章。
主要內(nèi)容:

Arraylist 與 LinkedList 異同

ArrayList 與 Vector 區(qū)別

HashMap的底層實(shí)現(xiàn)

HashMap 和 Hashtable 的區(qū)別

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

HashSet 和 HashMap 區(qū)別

ConcurrentHashMap 和 Hashtable 的區(qū)別

ConcurrentHashMap線程安全的具體實(shí)現(xiàn)方式/底層具體實(shí)現(xiàn)

集合框架底層數(shù)據(jù)結(jié)構(gòu)總結(jié)

本文會(huì)同步更新在我開源的Java學(xué)習(xí)指南倉庫 Java-Guide (一份涵蓋大部分Java程序員所需要掌握的核心知識(shí),正在一步一步慢慢完善,期待您的參與)中,地址:https://github.com/Snailclimb/Java-Guide,歡迎star、issue、pr。

Arraylist 與 LinkedList 異同

1. 是否保證線程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保證線程安全;

2. 底層數(shù)據(jù)結(jié)構(gòu): Arraylist 底層使用的是Object數(shù)組;LinkedList 底層使用的是雙向循環(huán)鏈表數(shù)據(jù)結(jié)構(gòu);

3. 插入和刪除是否受元素位置的影響:ArrayList 采用數(shù)組存儲(chǔ),所以插入和刪除元素的時(shí)間復(fù)雜度受元素位置的影響。 比如:執(zhí)行add(E e) 方法的時(shí)候, ArrayList 會(huì)默認(rèn)在將指定的元素追加到此列表的末尾,這種情況時(shí)間復(fù)雜度就是O(1)。但是如果要在指定位置 i 插入和刪除元素的話(add(int index, E element) )時(shí)間復(fù)雜度就為 O(n-i)。因?yàn)樵谶M(jìn)行上述操作的時(shí)候集合中第 i 和第 i 個(gè)元素之后的(n-i)個(gè)元素都要執(zhí)行向后位/向前移一位的操作。 ② LinkedList 采用鏈表存儲(chǔ),所以插入,刪除元素時(shí)間復(fù)雜度不受元素位置的影響,都是近似 O(1)而數(shù)組為近似 O(n)。

4. 是否支持快速隨機(jī)訪問: LinkedList 不支持高效的隨機(jī)元素訪問,而ArrayList 實(shí)現(xiàn)了RandmoAccess 接口,所以有隨機(jī)訪問功能??焖匐S機(jī)訪問就是通過元素的序號(hào)快速獲取元素對象(對應(yīng)于get(int index) 方法)。

5. 內(nèi)存空間占用: ArrayList的空 間浪費(fèi)主要體現(xiàn)在在list列表的結(jié)尾會(huì)預(yù)留一定的容量空間,而LinkedList的空間花費(fèi)則體現(xiàn)在它的每一個(gè)元素都需要消耗比ArrayList更多的空間(因?yàn)橐娣胖苯雍罄^和直接前驅(qū)以及數(shù)據(jù))。

補(bǔ)充:數(shù)據(jù)結(jié)構(gòu)基礎(chǔ)之雙向鏈表

雙向鏈表也叫雙鏈表,是鏈表的一種,它的每個(gè)數(shù)據(jù)結(jié)點(diǎn)中都有兩個(gè)指針,分別指向直接后繼和直接前驅(qū)。所以,從雙向鏈表中的任意一個(gè)結(jié)點(diǎn)開始,都可以很方便地訪問它的前驅(qū)結(jié)點(diǎn)和后繼結(jié)點(diǎn)。一般我們都構(gòu)造雙向循環(huán)鏈表,如下圖所示,同時(shí)下圖也是LinkedList 底層使用的是雙向循環(huán)鏈表數(shù)據(jù)結(jié)構(gòu)。

ArrayList 與 Vector 區(qū)別

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

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

HashMap的底層實(shí)現(xiàn) JDK1.8之前

JDK1.8 之前 HashMap 由 數(shù)組+鏈表 組成的(“鏈表散列” 即數(shù)組和鏈表的結(jié)合體),數(shù)組是 HashMap 的主體,鏈表則是主要為了解決哈希沖突而存在的(HashMap 采用 “拉鏈法也就是鏈地址法” 解決沖突),如果定位到的數(shù)組位置不含鏈表(當(dāng)前 entry 的 next 指向 null ),那么對于查找,添加等操作很快,僅需一次尋址即可;如果定位到的數(shù)組包含鏈表,對于添加操作,其時(shí)間復(fù)雜度依然為 O(1),因?yàn)樽钚碌?Entry 會(huì)插入鏈表頭部,急需要簡單改變引用鏈即可,而對于查找操作來講,此時(shí)就需要遍歷鏈表,然后通過 key 對象的 equals 方法逐一比對查找.

所謂 “拉鏈法” 就是將鏈表和數(shù)組相結(jié)合。也就是說創(chuàng)建一個(gè)鏈表數(shù)組,數(shù)組中每一格就是一個(gè)鏈表。若遇到哈希沖突,則將沖突的值加到鏈表中即可。

JDK1.8之后

相比于之前的版本, JDK1.8之后在解決哈希沖突時(shí)有了較大的變化,當(dāng)鏈表長度大于閾值(默認(rèn)為8)時(shí),將鏈表轉(zhuǎn)化為紅黑樹,以減少搜索時(shí)間。

TreeMap、TreeSet以及JDK1.8之后的HashMap底層都用到了紅黑樹。紅黑樹就是為了解決二叉查找樹的缺陷,因?yàn)槎娌檎覙湓谀承┣闆r下會(huì)退化成一個(gè)線性結(jié)構(gòu)。

推薦閱讀:

《Java 8系列之重新認(rèn)識(shí)HashMap》 :https://zhuanlan.zhihu.com/p/21673805

HashMap 和 Hashtable 的區(qū)別

線程是否安全: HashMap 是非線程安全的,HashTable 是線程安全的;HashTable 內(nèi)部的方法基本都經(jīng)過 synchronized 修飾。(如果你要保證線程安全的話就使用 ConcurrentHashMap 吧!);

效率: 因?yàn)榫€程安全的問題,HashMap 要比 HashTable 效率高一點(diǎn)。另外,HashTable 基本被淘汰,不要在代碼中使用它;

對Null key 和Null value的支持: HashMap 中,null 可以作為鍵,這樣的鍵只有一個(gè),可以有一個(gè)或多個(gè)鍵所對應(yīng)的值為 null。。但是在 HashTable 中 put 進(jìn)的鍵值只要有一個(gè) null,直接拋出 NullPointerException。

初始容量大小和每次擴(kuò)充容量大小的不同 : ①創(chuàng)建時(shí)如果不指定容量初始值,Hashtable 默認(rèn)的初始大小為11,之后每次擴(kuò)充,容量變?yōu)樵瓉淼?n+1。HashMap 默認(rèn)的初始化大小為16。之后每次擴(kuò)充,容量變?yōu)樵瓉淼?倍。②創(chuàng)建時(shí)如果給定了容量初始值,那么 Hashtable 會(huì)直接使用你給定的大小,而 HashMap 會(huì)將其擴(kuò)充為2的冪次方大小。也就是說 HashMap 總是使用2的冪作為哈希表的大小,后面會(huì)介紹到為什么是2的冪次方。

底層數(shù)據(jù)結(jié)構(gòu): JDK1.8 以后的 HashMap 在解決哈希沖突時(shí)有了較大的變化,當(dāng)鏈表長度大于閾值(默認(rèn)為8)時(shí),將鏈表轉(zhuǎn)化為紅黑樹,以減少搜索時(shí)間。Hashtable 沒有這樣的機(jī)制。

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

為了能讓 HashMap 存取高效,盡量較少碰撞,也就是要盡量把數(shù)據(jù)分配均勻,每個(gè)鏈表/紅黑樹長度大致相同。這個(gè)實(shí)現(xiàn)就是把數(shù)據(jù)存到哪個(gè)鏈表/紅黑樹中的算法。

這個(gè)算法應(yīng)該如何設(shè)計(jì)呢?

我們首先可能會(huì)想到采用%取余的操作來實(shí)現(xiàn)。但是,重點(diǎn)來了:“取余(%)操作中如果除數(shù)是2的冪次則等價(jià)于與其除數(shù)減一的與(&)操作(也就是說 hash%length==hash&(length-1)的前提是 length 是2的 n 次方;)。” 并且 采用二進(jìn)制位操作 &,相對于%能夠提高運(yùn)算效率,這就解釋了 HashMap 的長度為什么是2的冪次方。

HashSet 和 HashMap 區(qū)別

ConcurrentHashMap 和 Hashtable 的區(qū)別

ConcurrentHashMap 和 Hashtable 的區(qū)別主要體現(xiàn)在實(shí)現(xiàn)線程安全的方式上不同。

底層數(shù)據(jù)結(jié)構(gòu): JDK1.7的 ConcurrentHashMap 底層采用 分段的數(shù)組+鏈表 實(shí)現(xiàn),JDK1.8 采用的數(shù)據(jù)結(jié)構(gòu)跟HashMap1.8的結(jié)構(gòu)一樣,數(shù)組+鏈表/紅黑二叉樹。Hashtable 和 JDK1.8 之前的 HashMap 的底層數(shù)據(jù)結(jié)構(gòu)類似都是采用 數(shù)組+鏈表 的形式,數(shù)組是 HashMap 的主體,鏈表則是主要為了解決哈希沖突而存在的;

實(shí)現(xiàn)線程安全的方式(重要):在JDK1.7的時(shí)候,ConcurrentHashMap(分段鎖) 對整個(gè)桶數(shù)組進(jìn)行了分割分段(Segment),每一把鎖只鎖容器其中一部分?jǐn)?shù)據(jù),多線程訪問容器里不同數(shù)據(jù)段的數(shù)據(jù),就不會(huì)存在鎖競爭,提高并發(fā)訪問率。(默認(rèn)分配16個(gè)Segment,比Hashtable效率提高16倍。) 到了 JDK1.8 的時(shí)候已經(jīng)摒棄了Segment的概念,而是直接用 Node 數(shù)組+鏈表+紅黑樹的數(shù)據(jù)結(jié)構(gòu)來實(shí)現(xiàn),并發(fā)控制使用 synchronized 和 CAS 來操作。(JDK1.6以后 對 synchronized鎖做了很多優(yōu)化) 整個(gè)看起來就像是優(yōu)化過且線程安全的 HashMap,雖然在JDK1.8中還能看到 Segment 的數(shù)據(jù)結(jié)構(gòu),但是已經(jīng)簡化了屬性,只是為了兼容舊版本;② Hashtable(同一把鎖) :使用 synchronized 來保證線程安全,效率非常低下。當(dāng)一個(gè)線程訪問同步方法時(shí),其他線程也訪問同步方法,可能會(huì)進(jìn)入阻塞或輪詢狀態(tài),如使用 put 添加元素,另一個(gè)線程不能使用 put 添加元素,也不能使用 get,競爭會(huì)越來越激烈效率越低。

兩者的對比圖:

圖片來源:http://www.cnblogs.com/chengx...

HashTable:

JDK1.7的ConcurrentHashMap:

JDK1.8的ConcurrentHashMap(TreeBin: 紅黑二叉樹節(jié)點(diǎn)
Node: 鏈表節(jié)點(diǎn)):

ConcurrentHashMap線程安全的具體實(shí)現(xiàn)方式/底層具體實(shí)現(xiàn) JDK1.7(上面有示意圖)

首先將數(shù)據(jù)分為一段一段的存儲(chǔ),然后給每一段數(shù)據(jù)配一把鎖,當(dāng)一個(gè)線程占用鎖訪問其中一個(gè)段數(shù)據(jù)時(shí),其他段的數(shù)據(jù)也能被其他線程訪問。

ConcurrentHashMap 是由 Segment 數(shù)組結(jié)構(gòu)和 HahEntry 數(shù)組結(jié)構(gòu)組成

Segment 實(shí)現(xiàn)了 ReentrantLock,所以 Segment 是一種可重入鎖,扮演鎖的角色。HashEntry 用于存儲(chǔ)鍵值對數(shù)據(jù)。

static class Segment extends ReentrantLock implements Serializable {
}

一個(gè) ConcurrentHashMap 里包含一個(gè) Segment 數(shù)組。Segment 的結(jié)構(gòu)和HashMap類似,是一種數(shù)組和鏈表結(jié)構(gòu),一個(gè) Segment 包含一個(gè) HashEntry 數(shù)組,每個(gè) HashEntry 是一個(gè)鏈表結(jié)構(gòu)的元素,每個(gè) Segment 守護(hù)著一個(gè)HashEntry數(shù)組里的元素,當(dāng)對 HashEntry 數(shù)組的數(shù)據(jù)進(jìn)行修改時(shí),必須首先獲得對應(yīng)的 Segment的鎖。

JDK1.8 (上面有示意圖)

ConcurrentHashMap取消了Segment分段鎖,采用CAS和synchronized來保證并發(fā)安全。數(shù)據(jù)結(jié)構(gòu)跟HashMap1.8的結(jié)構(gòu)類似,數(shù)組+鏈表/紅黑二叉樹。

synchronized只鎖定當(dāng)前鏈表或紅黑二叉樹的首節(jié)點(diǎn),這樣只要hash不沖突,就不會(huì)產(chǎn)生并發(fā),效率又提升N倍。

集合框架底層數(shù)據(jù)結(jié)構(gòu)總結(jié) Collection 1. List

Arraylist: Object數(shù)組

Vector: Object數(shù)組

LinkedList: 雙向循環(huán)鏈表

2. Set

HashSet(無序,唯一): 基于 HashMap 實(shí)現(xiàn)的,底層采用 HashMap 來保存元素

LinkedHashSet: LinkedHashSet 繼承與 HashSet,并且其內(nèi)部是通過 LinkedHashMap 來實(shí)現(xiàn)的。有點(diǎn)類似于我們之前說的LinkedHashMap 其內(nèi)部是基于 Hashmap 實(shí)現(xiàn)一樣,不過還是有一點(diǎn)點(diǎn)區(qū)別的。

TreeSet(有序,唯一): 紅黑樹(自平衡的排序二叉樹。)

Map

HashMap: JDK1.8之前HashMap由數(shù)組+鏈表組成的,數(shù)組是HashMap的主體,鏈表則是主要為了解決哈希沖突而存在的(“拉鏈法”解決沖突).JDK1.8以后在解決哈希沖突時(shí)有了較大的變化,當(dāng)鏈表長度大于閾值(默認(rèn)為8)時(shí),將鏈表轉(zhuǎn)化為紅黑樹,以減少搜索時(shí)間

LinkedHashMap: LinkedHashMap 繼承自 HashMap,所以它的底層仍然是基于拉鏈?zhǔn)缴⒘薪Y(jié)構(gòu)即由數(shù)組和鏈表或紅黑樹組成。另外,LinkedHashMap 在上面結(jié)構(gòu)的基礎(chǔ)上,增加了一條雙向鏈表,使得上面的結(jié)構(gòu)可以保持鍵值對的插入順序。同時(shí)通過對鏈表進(jìn)行相應(yīng)的操作,實(shí)現(xiàn)了訪問順序相關(guān)邏輯。詳細(xì)可以查看:《LinkedHashMap 源碼詳細(xì)分析(JDK1.8)》

HashTable: 數(shù)組+鏈表組成的,數(shù)組是 HashMap 的主體,鏈表則是主要為了解決哈希沖突而存在的

TreeMap: 紅黑樹(自平衡的排序二叉樹)

推薦閱讀:

jdk1.8中ConcurrentHashMap的實(shí)現(xiàn)原理

HashMap? ConcurrentHashMap? 相信看完這篇沒人能難住你!

HASHMAP、HASHTABLE、CONCURRENTHASHMAP的原理與區(qū)別

ConcurrentHashMap實(shí)現(xiàn)原理及源碼分析

java-并發(fā)-ConcurrentHashMap高并發(fā)機(jī)制-jdk1.8

你若盛開,清風(fēng)自來。 歡迎關(guān)注我的微信公眾號(hào):“Java面試通關(guān)手冊”,一個(gè)有溫度的微信公眾號(hào)。公眾號(hào)有大量資料,回復(fù)關(guān)鍵字“1”你可能看到想要的東西哦!

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/76837.html

相關(guān)文章

  • 一名3年工作經(jīng)驗(yàn)的java程序員應(yīng)該具備的職業(yè)技能

    摘要:一名年工作經(jīng)驗(yàn)的程序員應(yīng)該具備的技能,這可能是程序員們比較關(guān)心的內(nèi)容。數(shù)據(jù)結(jié)構(gòu)和算法分析數(shù)據(jù)結(jié)構(gòu)和算法分析,對于一名程序員來說,會(huì)比不會(huì)好而且在工作中能派上用場。 一名3年工作經(jīng)驗(yàn)的Java程序員應(yīng)該具備的技能,這可能是Java程序員們比較關(guān)心的內(nèi)容。我這里要說明一下,以下列舉的內(nèi)容不是都要會(huì)的東西—-但是如果你掌握得越多,最終能得到的評價(jià)、拿到的薪水勢必也越高。 1、基本語法 這包括...

    renweihub 評論0 收藏0
  • 明天找python工作,看看幾道Python面試題吧,Python面試題No14

    摘要:定時(shí)檢測器定時(shí)拿出一部分重新的用過濾器進(jìn)行檢測剔除不能用的代理。重載是讓類以統(tǒng)一的方式處理不同類型數(shù)據(jù)的一種手段。雖然在內(nèi)存中存儲(chǔ)表數(shù)據(jù)確實(shí)會(huì)提供很高的性能,但當(dāng)守護(hù)進(jìn)程崩潰時(shí),所有的數(shù)據(jù)都會(huì)丟失。第1題: 如何解決驗(yàn)證碼的問題,用什么模塊,聽過哪些人工打碼平臺(tái)? PIL、pytesser、tesseract模塊 平臺(tái)的話有:(打碼平臺(tái)特殊,不保證時(shí)效性) 云打碼 掙碼 斐斐打碼 若快打碼...

    番茄西紅柿 評論0 收藏0
  • 明天找python工作,看看幾道Python面試題吧,Python面試題No14

    摘要:定時(shí)檢測器定時(shí)拿出一部分重新的用過濾器進(jìn)行檢測剔除不能用的代理。重載是讓類以統(tǒng)一的方式處理不同類型數(shù)據(jù)的一種手段。雖然在內(nèi)存中存儲(chǔ)表數(shù)據(jù)確實(shí)會(huì)提供很高的性能,但當(dāng)守護(hù)進(jìn)程崩潰時(shí),所有的數(shù)據(jù)都會(huì)丟失。第1題: 如何解決驗(yàn)證碼的問題,用什么模塊,聽過哪些人工打碼平臺(tái)? PIL、pytesser、tesseract模塊 平臺(tái)的話有:(打碼平臺(tái)特殊,不保證時(shí)效性) 云打碼 掙碼 斐斐打碼 若快打碼...

    李世贊 評論0 收藏0
  • 牛啤~這個(gè)框架被大量使用,騰訊開源的RPC框架阿里的Dubbo全靠它

    摘要:分布式高并發(fā)微服務(wù)問阿里京東螞蟻等大廠面試真題解析道跳槽漲薪必備精選面試題最新版大廠面試真題集點(diǎn)擊這里免費(fèi)領(lǐng)取點(diǎn)擊這里免費(fèi)領(lǐng)取 估計(jì)很多Java程序員平時(shí)主要的工作就是一些Web系統(tǒng)的業(yè)務(wù)開發(fā),對于服務(wù)端IO程序以及網(wǎng)絡(luò)通信編程做得并不多,但是對于高級或者資深程序員來說,IO通信以及服務(wù)端編...

    whidy 評論0 收藏0
  • 通俗易懂,JDK 并發(fā)容器總結(jié)

    摘要:線程安全的線程安全的,在讀多寫少的場合性能非常好,遠(yuǎn)遠(yuǎn)好于高效的并發(fā)隊(duì)列,使用鏈表實(shí)現(xiàn)。這樣帶來的好處是在高并發(fā)的情況下,你會(huì)需要一個(gè)全局鎖來保證整個(gè)平衡樹的線程安全。 該文已加入開源項(xiàng)目:JavaGuide(一份涵蓋大部分Java程序員所需要掌握的核心知識(shí)的文檔類項(xiàng)目,Star 數(shù)接近 14 k)。地址:https://github.com/Snailclimb... 一 JDK ...

    curlyCheng 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<