集合概述
什么是集合
集合框架:用于存儲數(shù)據(jù)的容器。
集合框架是為表示和操作集合而規(guī)定的一種統(tǒng)一的標(biāo)準(zhǔn)的體系結(jié)構(gòu)成福。任何集合框架都包含三大塊內(nèi)容:對外的接口敌蚜、接口的實現(xiàn)和對集合運算的算法。
接口:表示集合的抽象數(shù)據(jù)類型摆碉。接口允許我們操作集合時不必關(guān)注具體實現(xiàn),從而達(dá)到“多態(tài)”脓豪。在面向?qū)ο缶幊陶Z言中巷帝,接口通常用來形成規(guī)范。
實現(xiàn):集合接口的具體實現(xiàn)扫夜,是重用性很高的數(shù)據(jù)結(jié)構(gòu)楞泼。
算法:在一個實現(xiàn)了某個集合框架中的接口的對象身上完成某種有用的計算的方法,例如查找笤闯、排序等堕阔。這些算法通常是多態(tài)的,因為相同的方法可以在同一個接口被多個類實現(xiàn)時有不同的表現(xiàn)颗味。事實上超陆,算法是可復(fù)用的函數(shù)。它減少了程序設(shè)計的辛勞浦马。
集合框架通過提供有用的數(shù)據(jù)結(jié)構(gòu)和算法使你能集中注意力于你的程序的重要部分上时呀,而不是為了讓程序能正常運轉(zhuǎn)而將注意力于底層設(shè)計上。通過這些在無關(guān)API之間的簡易的互用性晶默,使你免除了為改編對象或轉(zhuǎn)換代碼以便聯(lián)合這些API而去寫大量的代碼谨娜。 它提高了程序速度和質(zhì)量。
集合的特點
集合的特點主要有如下兩點:
對象封裝數(shù)據(jù)磺陡,對象多了也需要存儲趴梢。集合用于存儲對象。
對象的個數(shù)確定可以使用數(shù)組仅政,對象的個數(shù)不確定的可以用集合垢油。因為集合是可變長度的。
集合和數(shù)組的區(qū)別
數(shù)組是固定長度的圆丹;集合可變長度的滩愁。
數(shù)組可以存儲基本數(shù)據(jù)類型,也可以存儲引用數(shù)據(jù)類型辫封;集合智能存儲引用數(shù)據(jù)類型硝枉。
數(shù)組存儲的元素必須是同一個數(shù)據(jù)類型廉丽;集合存儲的對象可以是不同數(shù)據(jù)類型。
使用集合框架的好處
容量自增長妻味;
提供了高性能的數(shù)據(jù)結(jié)構(gòu)和算法正压,使編碼更輕松,提高了程序速度和質(zhì)量责球;
允許不同 API 之間的互操作焦履,API之間可以來回傳遞集合;
可以方便地擴展或改寫集合雏逾,提高代碼復(fù)用性和可操作性嘉裤。
通過使用JDK自帶的集合類,可以降低代碼維護(hù)和學(xué)習(xí)新API成本栖博。
常用的集合類有哪些屑宠?
Map接口和Collection接口是所有集合框架的父接口:
Collection接口的子接口包括:Set接口和List接口Map接口的實現(xiàn)類主要有:HashMap、TreeMap仇让、Hashtable典奉、ConcurrentHashMap以及Properties等Set接口的實現(xiàn)類主要有:HashSet、TreeSet丧叽、LinkedHashSet等List接口的實現(xiàn)類主要有:ArrayList卫玖、LinkedList、Stack以及Vector等
List蠢正,Set骇笔,Map三者的區(qū)別?List嚣崭、Set笨触、Map 是否繼承自 Collection 接口?List雹舀、Map芦劣、Set 三個接口存取元素時,各有什么特點说榆?
集合框架底層數(shù)據(jù)結(jié)構(gòu)
Collection
List
Arraylist: Object數(shù)組
Vector: Object數(shù)組
LinkedList: 雙向循環(huán)鏈表
Set
HashSet(無序虚吟,唯一):底層采用 HashMap 來保存元素
LinkedHashSet: LinkedHashSet 繼承于HashSet,并且其內(nèi)部是通過 LinkedHashMap 來實現(xiàn)的签财。
TreeSet(有序串慰,唯一): 紅黑樹(自平衡的排序二叉樹。)
Map
HashMap: JDK1.8之前HashMap由數(shù)組+鏈表組成的唱蒸;JDK1.8以后鏈表+紅黑樹邦鲫;
LinkedHashMap:LinkedHashMap 繼承自 HashMap,所以它的底層仍然是基于拉鏈?zhǔn)缴⒘薪Y(jié)構(gòu)即由數(shù)組和鏈表或紅黑樹組成。另外庆捺,LinkedHashMap 在上面結(jié)構(gòu)的基礎(chǔ)上古今,增加了一條雙向鏈表,使得上面的結(jié)構(gòu)可以保持鍵值對的插入順序滔以。同時通過對鏈表進(jìn)行相應(yīng)的操作捉腥,實現(xiàn)了訪問順序相關(guān)邏輯。
HashTable: 數(shù)組+鏈表組成的你画,數(shù)組是 HashMap 的主體抵碟,鏈表則是主要為了解決哈希沖突而存在
TreeMap: 紅黑樹(自平衡的排序二叉樹)
哪些集合類是線程安全的?
vector:就比arraylist多了個同步化機制(線程安全)撬即,因為效率較低立磁,現(xiàn)在已經(jīng)不太建議使用。在web應(yīng)用中剥槐,特別是前臺頁面,往往效率(頁面響應(yīng)速度)是優(yōu)先考慮的宪摧。
statck:堆棧類粒竖,先進(jìn)后出。
hashtable:就比hashmap多了個線程安全几于。
enumeration:枚舉蕊苗,相當(dāng)于迭代器。
Java集合的快速失敗機制 “fail-fast”沿彭?
是java集合的一種錯誤檢測機制朽砰,當(dāng)多個線程對集合進(jìn)行結(jié)構(gòu)上的改變的操作時,有可能會產(chǎn)生 fail-fast 機制喉刘。
例如:假設(shè)存在兩個線程(線程1瞧柔、線程2),線程1通過Iterator在遍歷集合A中的元素睦裳,在某個時候線程2修改了集合A的結(jié)構(gòu)(是結(jié)構(gòu)上面的修改造锅,而不是簡單的修改集合元素的內(nèi)容),那么這個時候程序就會拋出 ConcurrentModificationException 異常廉邑,從而產(chǎn)生fail-fast機制哥蔚。
原因:迭代器在遍歷時直接訪問集合中的內(nèi)容,并且在遍歷過程中使用一個 modCount 變量蛛蒙。集合在被遍歷期間如果內(nèi)容發(fā)生變化糙箍,就會改變modCount的值。每當(dāng)?shù)魇褂胔ashNext()/next()遍歷下一個元素之前牵祟,都會檢測modCount變量是否為expectedmodCount值深夯,是的話就返回遍歷;否則拋出異常课舍,終止遍歷塌西。
解決辦法:
在遍歷過程中他挎,所有涉及到改變modCount值的地方全部加上synchronized。
使用CopyOnWriteArrayList來替換ArrayList
怎么確保一個集合不能被修改捡需?
可以使用 Collections. unmodifiableCollection(Collection c) 方法來創(chuàng)建一個只讀集合办桨,這樣改變集合的任何操作都會拋出 Java. lang. UnsupportedOperationException 異常。
Collection接口
List接口
迭代器 Iterator 是什么站辉?
Iterator 接口提供遍歷任何 Collection 的接口呢撞。迭代器取代了 Java 集合框架中的 Enumeration,迭代器允許調(diào)用者在迭代過程中移除元素饰剥。
Iterator 怎么使用殊霞?有什么特點?
Iterator 的特點是只能單向遍歷汰蓉,但是更加安全绷蹲,因為它可以確保,在當(dāng)前遍歷的集合元素被更改的時候顾孽,就會拋出 ConcurrentModificationException 異常祝钢。
如何邊遍歷邊移除 Collection 中的元素?
邊遍歷邊修改 Collection 的唯一正確方式是使用 Iterator.remove() 方法
Iterator 和 ListIterator 有什么區(qū)別若厚?
Iterator 可以遍歷 Set 和 List 集合拦英,而 ListIterator 只能遍歷 List。
Iterator 只能單向遍歷测秸,而 ListIterator 可以雙向遍歷(向前/后遍歷)疤估。
ListIterator 實現(xiàn) Iterator 接口,然后添加了一些額外的功能霎冯,比如添加一個元素铃拇、替換一個元素、獲取前面或后面元素的索引位置肃晚。
遍歷一個 List 有哪些不同的方式锚贱?每種方法的實現(xiàn)原理是什么?Java 中 List 遍歷的最佳實踐是什么关串?
for 循環(huán)遍歷拧廊,基于計數(shù)器。在集合外部維護(hù)一個計數(shù)器晋修,然后依次讀取每一個位置的元素墓卦,當(dāng)讀取到最后一個元素后停止尿庐。
迭代器遍歷枉疼,Iterator。Iterator 是面向?qū)ο蟮囊粋€設(shè)計模式褪测,目的是屏蔽不同數(shù)據(jù)集合的特點,統(tǒng)一遍歷集合的接口。Java 在 Collections 中支持了 Iterator 模式。
foreach 循環(huán)遍歷通今。foreach 內(nèi)部也是采用了 Iterator 的方式實現(xiàn)臼氨,使用時不需要顯式聲明 Iterator 或計數(shù)器褂乍。優(yōu)點是代碼簡潔题诵,不易出錯草冈;缺點是只能做簡單的遍歷怎棱,不能在遍歷過程中操作數(shù)據(jù)集合,例如刪除绷跑、替換拳恋。
推薦的做法就是,支持 Random Access 的列表可用 for 循環(huán)遍歷砸捏,否則建議用 Iterator 或 foreach 遍歷谬运。
說一下 ArrayList 的優(yōu)缺點
優(yōu)點:隨機訪問快
缺點:插入刪除需復(fù)制,耗費性能
如何實現(xiàn)數(shù)組和 List 之間的轉(zhuǎn)換垦藏?
數(shù)組轉(zhuǎn) List:使用 Arrays. asList(array) 進(jìn)行轉(zhuǎn)換梆暖。
List 轉(zhuǎn)數(shù)組:使用 List 自帶的 toArray() 方法。
ArrayList 和 LinkedList 的區(qū)別是什么掂骏?
數(shù)據(jù)結(jié)構(gòu)實現(xiàn):ArrayList 動態(tài)數(shù)組轰驳,而 LinkedList 雙向鏈表隨機訪問效率:ArrayList 更好增加和刪除效率:LinkedList 更好內(nèi)存空間占用:LinkedList 比 ArrayList 更占內(nèi)存,因為 LinkedList 的節(jié)點除了存儲數(shù)據(jù)弟灼,還存儲了兩個應(yīng)用線程安全:都不保證線程安全级解;綜合來說,在需要頻繁讀取集合中的元素時袜爪,更推薦使用 ArrayList蠕趁,而在插入和刪除操作較多時,更推薦使用 LinkedList辛馆。
ArrayList 和 Vector 的區(qū)別是什么俺陋?
線程安全:Vector 使用了 Synchronized 來實現(xiàn)線程同步豁延,是線程安全的,而 ArrayList 是非線程安全的腊状。
性能:ArrayList 在性能方面要優(yōu)于 Vector诱咏。
擴容:ArrayList 和 Vector 都會根據(jù)實際的需要動態(tài)的調(diào)整容量,只不過在 Vector 擴容每次會增加 1 倍缴挖,而 ArrayList 只會增加 50%袋狞。
插入數(shù)據(jù)時,ArrayList映屋、LinkedList苟鸯、Vector誰速度較快?闡述 ArrayList棚点、Vector早处、LinkedList 的存儲性能和特性?
ArrayList瘫析、Vector 底層數(shù)組方式存儲數(shù)據(jù)砌梆。
LinkedList 雙向鏈表,LinkedList 插入速度較快贬循。
多線程場景下如何使用 ArrayList咸包?
ArrayList 不是線程安全的,如果遇到多線程場景杖虾,可以通過 Collections 的 synchronizedList 方法將其轉(zhuǎn)換成線程安全的容器后再使用
為什么 ArrayList 的 elementData 加上 transient 修飾烂瘫?
每次序列化時,先調(diào)用 defaultWriteObject() 方法序列化 ArrayList 中的非 transient 元素奇适,然后遍歷 elementData忱反,只序列化已存入的元素,這樣既加快了序列化的速度滤愕,又減小了序列化之后的文件大小。
List 和 Set 的區(qū)別
list: 有序 元素可重復(fù) 多個null 有索引 for和iterator 檢索低效 插入刪除高效
set: 無序 不可重復(fù) 一個null iterator 查找高效 插入刪除低效
Set接口
說一下 HashSet 的實現(xiàn)原理怜校?
HashSet: 底層HashMap hashmap的value統(tǒng)一為PRESENT 底層調(diào)用hashmap的方法 hashset不允許重復(fù)
HashSet如何檢查重復(fù)?HashSet是如何保證數(shù)據(jù)不可重復(fù)的?
檢查重復(fù)压状,不僅比較hash值碉输,還要結(jié)合equals方法
值作為hashmap的key,所以不會重復(fù)
Queue
BlockingQueue是什么裙顽?
阻塞隊列 在進(jìn)行檢索或移除一個元素的時候付燥,它會等待隊列變?yōu)榉强眨划?dāng)在添加一個元素時愈犹,它會等待隊列中的可用空間
在 Queue 中 poll()和 remove()有什么區(qū)別键科?
相同點:返回第一元素闻丑,并刪除
不同點:沒有元素,poll返回null remove拋出異常NoSuchElementException
Map接口
說一下 HashMap 的實現(xiàn)原理勋颖?
概述: HashMap是基于哈希表的Map接口的非同步實現(xiàn)
數(shù)組和鏈表的結(jié)合體
1.用key的hashcode作hash計算下標(biāo)
2.(1)key相同嗦嗡,覆蓋原始值;(2)key不同(出現(xiàn)沖突)饭玲,key-value放入鏈表
Jdk 1.8中對HashMap的實現(xiàn)做了優(yōu)化侥祭,當(dāng)鏈表中的節(jié)點數(shù)據(jù)超過八個之后,該鏈表會轉(zhuǎn)為紅黑樹來提高查詢效率茄厘,從原來的O(n)到O(logn)
HashMap在JDK1.7和JDK1.8中有哪些不同矮冬?HashMap的底層實現(xiàn)
JDK1.8之前: 數(shù)據(jù)+鏈表; 之后:鏈表長度大于閾值(默認(rèn)為8)次哈,鏈表轉(zhuǎn)為紅黑樹
HashMap的put方法的具體流程胎署?
①.判斷鍵值對數(shù)組table是否為空或為null,否則執(zhí)行resize()進(jìn)行擴容亿乳;
②.根據(jù)鍵值key計算hash值得到插入的數(shù)組索引i硝拧,如果table[i]==null,直接新建節(jié)點添加葛假,轉(zhuǎn)向⑥障陶,如果table[i]不為空,轉(zhuǎn)向③聊训;
③.判斷table[i]的首個元素是否和key一樣抱究,如果相同直接覆蓋value,否則轉(zhuǎn)向④带斑,這里的相同指的是hashCode以及equals鼓寺;
④.判斷table[i] 是否為treeNode,即table[i] 是否是紅黑樹勋磕,如果是紅黑樹妈候,則直接在樹中插入鍵值對,否則轉(zhuǎn)向⑤挂滓;
⑤.遍歷table[i]苦银,判斷鏈表長度是否大于8,大于8的話把鏈表轉(zhuǎn)換為紅黑樹赶站,在紅黑樹中執(zhí)行插入操作幔虏,否則進(jìn)行鏈表的插入操作;遍歷過程中若發(fā)現(xiàn)key已經(jīng)存在直接覆蓋value即可贝椿;
⑥.插入成功后想括,判斷實際存在的鍵值對數(shù)量size是否超過了最大容量threshold,如果超過烙博,進(jìn)行擴容瑟蜈。
HashMap的擴容操作是怎么實現(xiàn)的烟逊?
①.在jdk1.8中,resize方法是在hashmap中的鍵值對大于閥值時或者初始化時踪栋,就調(diào)用resize方法進(jìn)行擴容焙格;
②.每次擴展的時候,都是擴展2倍夷都;
③.擴展后Node對象的位置要么在原位置眷唉,要么移動到原偏移量兩倍的位置。
HashMap是怎么解決哈希沖突的囤官?
什么是哈希:就是把任意長度的輸入通過散列算法冬阳,變換成固定長度的輸出,該輸出就是散列值(哈希值)
基本特性:根據(jù)同一散列函數(shù)計算出的散列值如果不同党饮,那么輸入值肯定也不同肝陪。但是,根據(jù)同一散列函數(shù)計算出的散列值如果相同刑顺,輸入值不一定相同
什么是哈希沖突:當(dāng)兩個不同的輸入值氯窍,根據(jù)同一散列函數(shù)計算出相同的散列值的現(xiàn)象,我們就把它叫做碰撞(哈希碰撞)
HashMap的數(shù)據(jù)結(jié)構(gòu):數(shù)組的特點是:尋址容易蹲堂,插入和刪除困難狼讨;鏈表的特點是:尋址困難,但插入和刪除容易
hash()函數(shù):與自己右移16位進(jìn)行異或運算(高低位異或)
能否使用任何類作為 Map 的 key柒竞?
可以政供,考慮一下幾點:
1.重寫了 equals() 方法,也應(yīng)該重寫 hashCode() 方法朽基。
2.遵循與 equals() 和 hashCode() 相關(guān)的規(guī)則布隔。
3.用戶自定義 Key 類最佳實踐是使之為不可變的
為什么HashMap中String、Integer這樣的包裝類適合作為Key稼虎?
1.都是final類型衅檀,即不可變性,保證key的不可更改性霎俩,不會存在獲取hash值不同的情況
2.內(nèi)部已重寫了equals()术吝、hashCode()等方法,遵守了HashMap內(nèi)部的規(guī)范
如果使用Object作為HashMap的Key茸苇,應(yīng)該怎么辦呢?
重寫hashCode()和equals()方法
HashMap為什么不直接使用hashCode()處理后的哈希值直接作為table的下標(biāo)沦寂?
hashCode()方法返回的是int整數(shù)類型学密,其范圍為-(2 ^ 31)~(2 ^ 31 - 1),約有40億個映射空間传藏;哈希值可能不在數(shù)組大小范圍內(nèi)腻暮,進(jìn)而無法匹配存儲位置
HashMap 的長度為什么是2的冪次方
hash%length==hash&(length-1)的前提是 length 是2的 n 次方彤守;
HashMap 與 HashTable 有什么區(qū)別?
1.線程安全 hashtable用synchronized修飾
2.效率 hashmap效率高
3.對null key的支持 hashmap可以 hashtable報錯
4.Hashtable 默認(rèn)大小11哭靖,之后擴充具垫,容量為原來2n+1。HashMap 默認(rèn)大小16试幽。擴充筝蚕,原來的2倍
如何決定使用 HashMap 還是 TreeMap?
對于在Map中插入铺坞、刪除和定位元素起宽,HashMap最好。然而济榨,對一個有序的key集合進(jìn)行遍歷坯沪,TreeMap更好
HashMap 和 ConcurrentHashMap 的區(qū)別
1.JDK1.8之后ConcurrentHashMap啟用了一種全新的方式實現(xiàn),利用CAS算法。
2.hashmap允許null
ConcurrentHashMap 和 Hashtable 的區(qū)別擒滑?
1.底層數(shù)據(jù)結(jié)構(gòu)腐晾,ConcurrentHashMap:數(shù)組+鏈表/紅黑二叉樹;Hashtable:數(shù)組+鏈表
2.實現(xiàn)線程安全的方式(重要):① 在JDK1.7的時候丐一,ConcurrentHashMap(分段鎖) 對整個桶數(shù)組進(jìn)行了分割分段(Segment)藻糖,每一把鎖只鎖容器其中一部分?jǐn)?shù)據(jù),多線程訪問容器里不同數(shù)據(jù)段的數(shù)據(jù)钝诚,就不會存在鎖競爭颖御,提高并發(fā)訪問率。(默認(rèn)分配16個Segment凝颇,比Hashtable效率提高16倍潘拱。) 到了 JDK1.8 的時候已經(jīng)摒棄了Segment的概念,而是直接用 Node 數(shù)組+鏈表+紅黑樹的數(shù)據(jù)結(jié)構(gòu)來實現(xiàn)拧略,并發(fā)控制使用 synchronized 和 CAS 來操作芦岂。(JDK1.6以后 對 synchronized鎖做了很多優(yōu)化) 整個看起來就像是優(yōu)化過且線程安全的 HashMap,雖然在JDK1.8中還能看到 Segment 的數(shù)據(jù)結(jié)構(gòu)垫蛆,但是已經(jīng)簡化了屬性禽最,只是為了兼容舊版本;② Hashtable(同一把鎖) :使用 synchronized 來保證線程安全袱饭,效率非常低下川无。當(dāng)一個線程訪問同步方法時,其他線程也訪問同步方法虑乖,可能會進(jìn)入阻塞或輪詢狀態(tài)懦趋,如使用 put 添加元素,另一個線程不能使用 put 添加元素疹味,也不能使用 get仅叫,競爭會越來越激烈效率越低帜篇。
ConcurrentHashMap 底層具體實現(xiàn)知道嗎?實現(xiàn)原理是什么诫咱?
JDK1.7: ConcurrentHashMap采用Segment + HashEntry的方式進(jìn)行實現(xiàn)
JDK1.8: synchronized只鎖定當(dāng)前鏈表或紅黑二叉樹的首節(jié)點
Array 和 ArrayList 有何區(qū)別笙隙?
Array 存儲基本數(shù)據(jù)類型和對象,ArrayList 只能存儲對象坎缭。Array 是指定固定大小的竟痰,而 ArrayList 大小是自動擴展的。Array 內(nèi)置方法沒有 ArrayList 多幻锁,比如 addAll凯亮、removeAll、iteration 等方法只有 ArrayList 有哄尔。
如何實現(xiàn) Array 和 List 之間的轉(zhuǎn)換假消?
Array 轉(zhuǎn) List: Arrays. asList(array) ;
List 轉(zhuǎn) Array:List 的 toArray() 方法岭接。
comparable 和 comparator的區(qū)別富拗?
comparable接口實際上是出自java.lang包,它有一個 compareTo(Object obj)方法用來排序
comparator接口實際上是出自 java.util 包鸣戴,它有一個compare(Object obj1, Object obj2)方法用來排序
Collection 和 Collections 有什么區(qū)別啃沪?
java.util.Collection 是一個集合接口(集合類的一個頂級接口)。它提供了對集合對象進(jìn)行基本操作的通用接口方法窄锅。Collection接口在Java 類庫中有很多具體的實現(xiàn)创千。Collection接口的意義是為各種具體的集合提供了最大化的統(tǒng)一操作方式,其直接繼承接口有List與Set入偷。
Collections則是集合類的一個工具類/幫助類追驴,其中提供了一系列靜態(tài)方法,用于對集合中元素進(jìn)行排序疏之、搜索以及線程安全等各種操作殿雪。
TreeMap 和 TreeSet 在排序時如何比較元素?Collections 工具類中的 sort()方法如何比較元素锋爪?
TreeSet 要求存放的對象所屬的類必須實現(xiàn) Comparable 接口丙曙,該接口提供了比較元素的 compareTo()方法,當(dāng)插入元素時會回調(diào)該方法比較元素的大小其骄。TreeMap 要求存放的鍵值對映射的鍵必須實現(xiàn) Comparable 接口從而根據(jù)鍵對元素進(jìn) 行排 序亏镰。
Collections 工具類的 sort 方法有兩種重載的形式,
第一種要求傳入的待排序容器中存放的對象比較實現(xiàn) Comparable 接口以實現(xiàn)元素的比較拯爽;
第二種不強制性的要求容器中的元素必須可比較拆挥,但是要求傳入第二個參數(shù),參數(shù)是Comparator 接口的子類型(需要重寫 compare 方法實現(xiàn)元素的比較),相當(dāng)于一個臨時定義的排序規(guī)則纸兔,其實就是通過接口注入比較元素大小的算法,也是對回調(diào)模式的應(yīng)用(Java 中對函數(shù)式編程的支持)否副。
面試造火箭汉矿,工作擰螺絲,希望對你有所幫助
多多轉(zhuǎn)發(fā)备禀、點贊洲拇、評論、謝謝大家曲尸,讓更多人受益8承!另患!