筆者能力有限,總結(jié)有誤的地方,請(qǐng)讀者協(xié)作更正。
1.HashMap和HashTable和ConcurrentHashMap?
1)HashMap和HashTable的區(qū)別?
HashMap可以接受null;HashTable不可以;
HashMap是非線程安全的,存儲(chǔ)的是鍵值對(duì),速度很快;
HashTable是線程安全的,但是不推薦使用
2)HashMap的put()和get()方法?
HashMap基于hashing原理,使用put將key-value對(duì)象到HashMap中;使用get獲取存儲(chǔ)的對(duì)象;
當(dāng)我們put的時(shí)候,先調(diào)用key的hashCode()方法,返回HashCode用于找到bucket位置來存儲(chǔ)Entry對(duì)象;
3)HashMap的碰撞探測(cè)以及碰撞探測(cè)的解決方法? 當(dāng)兩個(gè)對(duì)象的HashCode相同時(shí)會(huì)發(fā)生什么?
因?yàn)镠ashCode相關(guān),它們的bucket位置相同,碰撞就會(huì)發(fā)生。因?yàn)镠ashMap使用鏈表存儲(chǔ)對(duì)象,這個(gè)Entry(包含鍵值對(duì)的Map.Entry對(duì)象)會(huì)存儲(chǔ)在鏈表中。
4)如果兩個(gè)鍵的hashCode相同,如何獲取鍵值對(duì)對(duì)象?
調(diào)用get方法,通過鍵值對(duì)的hashCode找到bucket的位置,會(huì)調(diào)用keys.equals( )方法去鏈表中找到對(duì)象。
使用不可變的,聲明為final的對(duì)象,能減少碰撞的發(fā)生,提供效率; 由于鍵值對(duì)的不可變性,使用String,interger這樣的包裝類能有效的提供獲取對(duì)象的速度;
5)HashMap的大小超過了負(fù)載因子(load factor)定義的容量,怎么辦?
默認(rèn)負(fù)載因子大小是0.75;初始大小是16;
當(dāng)一個(gè)map填滿了75%的buckey時(shí)候,會(huì)創(chuàng)建原來HashMap大小兩倍的bucket數(shù)組,來重新調(diào)整map的大小,并將原來的對(duì)象放入新的bucket數(shù)組中;
6)重新調(diào)整HashMap大小存在什么問題?
可能會(huì)產(chǎn)生條件競(jìng)爭(zhēng); 因?yàn)樵谥匦抡{(diào)整大小的時(shí)候,存儲(chǔ)在鏈表的元素的次序會(huì)反過來,HashMap并不會(huì)將元素放在鏈表的尾部,而是放在頭部,避免尾部遍歷; 條件競(jìng)爭(zhēng)產(chǎn)生,就會(huì)死循環(huán); 多線程情況下,不使用HashMap,它是非線程安全的,通常都使用線程安全的CurrentHashMap;
7)為什么String,integer這樣的wrappr類適合作為鍵?
String最常用,因?yàn)榘b類是final的,不可變的,已經(jīng)重寫了equals()hashCode()方法; 計(jì)算hashCode,是為了防止鍵值改變;不可變性能減少hash碰撞,提升HashMap性能;
8)我們可以使用自定義的對(duì)象作為鍵么?
可以使用任何對(duì)象作為鍵,但是需要遵循equals和hashcode方法的規(guī)則,最重要的是要確保作為鍵值的對(duì)象插入Map之后不可變。
9)可以使用ConcurrentHashMap替代hashTable么?
Hashtable是線程安全的,但是ConcurrentHashMap同步性更好; ConcurrentHashMap在內(nèi)部使用了同步鎖,只鎖住一部分; 當(dāng)然可以替代Hashtable,但是線程安全性沒有hashTable高;
2.談一談HashMap的工作原理?
HashMap基于hashing原理,通過put()和get()方法來存儲(chǔ)對(duì)象和獲取對(duì)象;
我們將鍵值對(duì)傳給put()時(shí),它調(diào)用鍵對(duì)象的hashcode()方法來計(jì)算hash值,然后找到bucket位置來存儲(chǔ)值對(duì)象;
獲取對(duì)象的時(shí)候,通過鍵對(duì)象的equals()方法找到正確的鍵值對(duì),然后返回值對(duì)象;
HashMap使用鏈表來解決碰撞問題,當(dāng)碰撞發(fā)生時(shí),對(duì)象會(huì)存儲(chǔ)到鏈表的下一個(gè)節(jié)點(diǎn),hashMap在每個(gè)鏈表節(jié)點(diǎn)中存儲(chǔ)鍵值對(duì)對(duì)象。
兩個(gè)不同的鍵值對(duì)象的Hashcode相同時(shí)候,會(huì)將它存儲(chǔ)到同個(gè)bucket位置的鏈表中,通過鍵值對(duì)的equals()方法來找到鍵值對(duì)。
HashMap的好處非常多,在電子商務(wù)的應(yīng)用中使用HashMap作為緩存,考慮到性能和非線程安全性,常用ConcurentHashMap代替HashMap;
3.為什么Map接口不繼承Collection接口?
. Set是無序集合,并且不允許重復(fù)的元素
· List是有序的集合,并且允許重復(fù)的元素
·Map被設(shè)計(jì)為鍵值對(duì)的集合,不是一組對(duì)象規(guī)范,所以不需要繼承Collection 接口
4.Comparable和comparator的不同之處?
Comparable接口來自java.lang包,它有一個(gè)compareTo(Object obj)方法用來給Object排序
Comparator接口是java.util包,他有一個(gè)compare(Object obj1, Object obj2)方法用來給objects排序
5.如何對(duì)Object的List進(jìn)行排序?
對(duì)數(shù)組,使用Arrays.sort( )方法 對(duì)集合,使用Collections.sort( )方法
6.Java中set和List的區(qū)別?
Set:無序,不可重復(fù);沒有索引,僅僅允許一個(gè)null值,類有HashSet、LinkedHashMap、TreeSet
List:有序,可以重復(fù);有索引,允許多個(gè)null值,可以按照插入順序顯示,類有Vector、ArrayList、LinkedList
7.ArrayList和Vector的區(qū)別?
Vector是同步的,ArrayList是不同步的,ArrayList是集合框架的組成部分
8.如何保證一個(gè)集合線程安全?
Vector、HashTable、Properties和Stack是同步的,是線程安全的;
使用Collections.synchronizedList( )方法,可以保證List線程安全;
使用Collections.synchronizedSet( )方法可以保證set類線程安全;
9.HashCode()和equals()方法的重要性?如何使用?
HashCode()和equals()方法定義在Object類中;
如果Equals()方法比較兩個(gè)對(duì)象返回true,那么它們的HashCode()的返回值一樣
10.Java集合框架是什么?說出集合框架的優(yōu)點(diǎn)?
看圖描述;
好處:減少開發(fā)成本,代碼質(zhì)量提高,減少維護(hù),復(fù)用性高等。
11.Iterater和ListIterator之間的區(qū)別?
Iterater使用來遍歷set和list集合,只能向前遍歷
ListIterator只可以遍歷List集合,可以雙向遍歷 ListIterator繼承iterator;
12.遍歷List集合的同步方式?
使用for-each循環(huán); 使用迭代器 List<String> strList = new ArrayList<>(); //1. 使用for-each循環(huán) for(String obj : strList){ System.out.println(obj); }
//2. using iterator
Iterator<String> it = strList.iterator();
while(it.hasNext()){
String obj = it.next();
System.out.println(obj);
}
13.在迭代一個(gè)集合的時(shí)候,怎樣避免ConcurrentModificationException?
能夠使用并發(fā)集合類來避免ConcurrentModificationException,比方使用CopyOnWriteArrayList。 而不是ArrayList。
14.為何Iterator接口沒有詳細(xì)的實(shí)現(xiàn)?
接口只提供規(guī)范,為何要實(shí)現(xiàn),誰要實(shí)現(xiàn),誰來提供方法
15.Map接口提供了哪些不同的集合視圖?
Set keyset():返回map中包括的全部key的一個(gè)Set視圖。
Collection values():返回一個(gè)map中包括的全部value的一個(gè)Collection視圖。
Set<Map.Entry<K,V>> entrySet():返回一個(gè)map中包括的全部映射的一個(gè)集合視圖。
16.怎樣決定選用HashMap還是TreeMap?
對(duì)于在Map中插入、刪除和定位元素這類操作,HashMap是最好的選擇。然而。假如你須要對(duì)一個(gè)有序的key集合進(jìn)行遍歷,TreeMap是更好的選擇。
基于你的collection的大小,或許向HashMap中加入元素會(huì)更快。將map換為TreeMap進(jìn)行有序key的遍歷。
17.EnumSet是什么?
是枚舉類的集合實(shí)現(xiàn)
18.BlockingQueue是什么?
是隊(duì)列,是集合框架的一部分,主要用于實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者模式
19.怎樣對(duì)一組對(duì)象進(jìn)行排序?
假設(shè)我們需要對(duì)一個(gè)對(duì)象數(shù)組進(jìn)行排序,我們能夠使用Arrays.sort()方法。 假設(shè)我們須要排序一個(gè)對(duì)象列表,我們能夠使用Collection.sort()方法。
20.集合框架了實(shí)現(xiàn)了哪些通用算法?
Java集合框架提供經(jīng)常使用的算法實(shí)現(xiàn),比方排序和搜索。Collections類包括這些方法實(shí)現(xiàn)。大部分算法是操作List的,但一部分對(duì)全部類型的集合都是可用的。部分算法有排序、搜索、混編、最大最小值。
21.與Java集合框架相關(guān)的有哪些最好的實(shí)踐?
(1)依據(jù)需要選擇正確的集合類型。比方,假設(shè)指定了大小,我們會(huì)選用Array而非ArrayList。
假設(shè)我們想依據(jù)插入順序遍歷一個(gè)Map,我們須要使用TreeMap。假設(shè)我們不想反復(fù)。我們應(yīng)該使用Set。
(2)一些集合類同意指定初始容量。所以假設(shè)我們能夠預(yù)計(jì)到存儲(chǔ)元素的數(shù)量,我們能夠使用它,就避免了又一次哈?;虼笮≌{(diào)整。
(3)基于接口編程,而非基于實(shí)現(xiàn)編程。它同意我們后來輕易地改變實(shí)現(xiàn)。
(4)總是使用類型安全的泛型。避免在執(zhí)行時(shí)出現(xiàn)ClassCastException。
(5)使用JDK提供的不可變類作為Map的key,能夠避免自己實(shí)現(xiàn)hashCode()和equals()。
(6)盡可能使用Collections工具類,或者獲取僅讀、同步或空的集合,而非編寫自己的實(shí)現(xiàn)。
它將會(huì)提供代碼重用性,它有著更好的穩(wěn)定性和可維護(hù)性。
圖1:
圖2:
圖3:
更多建議: