3到5年工作經驗是如何回答面試中被問到的Java集合框架問題
可能很多人會問Java集合真的那麼重要嗎,就像為什麼現在很多企業都喜歡先問演算法一樣,目的就是考察你對Java基礎掌握的程度如何。下面我將列出了一些關於Java集合的重要問題,讓我們一起看看3到5年的Java開發工程師是如何回答這些問題的。
Java集合中 List、Set、Map 之間的區別
比較/集合 | List | Set | Map |
元素 | 可以重複 | 不可重複(equals比較) | 鍵必須唯一,但是值可以重複 |
順序 | 有序 | 無序(有hashcode決定) | 無序 |
常用方法 | add( )、remove( )、clear( )、get( )、contains( )、size( ) | add( )、remove( )、clear( )、contains( )、size( ) | put( )、get( )、remove( )、clear( )、containsKey( )、containsValue( )、keySet( )、values( )、size( ) |
常見實現類 | ArrayList、LinkedList、Vector | HashSet、LinkedHashSet、TreeSet | HashMap、HashTable |
允許插入null | 可以插入多個null | 只允許插入一個null | 鍵只允許插入一個null,值可以插入多個null值 |
一、淺談一下ArrayList和LinkedList各自的優缺點
- 順序插入速度ArrayList會比較快,因為ArrayList是基於陣列實現的,陣列是事先new好的,只要往指定位置塞一個數據就好了;LinkedList則不同,每次順序插入的時候LinkedList將new一個物件出來,如果物件比較大,那麼new的時間勢必會長一點,再加上一些引用賦值的操作,所以順序插入LinkedList必然慢於ArrayList。
- 基於上一點,因為LinkedList裡面不僅維護了待插入的元素,還維護了Entry(單向連結串列)的前置Entry和後繼Entry,如果一個LinkedList中的Entry非常多,那麼LinkedList將比ArrayList更耗費一些記憶體。
- 資料遍歷的速度,使用各自遍歷效率最高的方式,ArrayList的遍歷效率會比LinkedList的遍歷效率高一些。
- LinkedList做插入、刪除的時候,慢在定址,快在只需要改變前後Entry(單向連結串列)的引用地址。ArrayList做插入、刪除的時候,慢在陣列元素的批量copy,快在定址。
二、使用LinkedList實現堆疊和佇列
1.堆疊:是一種先進後出的資料結構(容器),就像彈夾一樣(壓子彈)
2.佇列:先進先出(當多個任務分配給印表機時,為了防止衝突,建立一個佇列,把任務入隊,按先入先出的原則處理任務。當多個使用者要訪問遠端服務端的檔案時,也用到佇列,滿足先來先服務的原則。)
三、for迴圈和foreach遍歷集合哪個更快
1.當遍歷陣列結構的集合時用for或者foreach都行,在固定長度或長度不需要計算的時候for迴圈效率高於foreach。
2.在不確定長度或者計算長度有損效能的時候用foreach比較方便。
3.對於陣列來說,for和foreach迴圈效率差不多,但是對於連結串列來說,for迴圈效率明顯比foreach低。
如果使用foreach,當資料量大的時候有可能會導致系統崩潰,為什麼會很糟糕,因為for迴圈時要獲取第i個元素必須從頭開始遍歷,而iterator遍歷就是從頭開始遍歷,遍歷完只需要一次(foreach迴圈就是用的iterator)。
四、如何快速的遍歷map集合,哪種方式最快?
map.entrySet即可,entrySet的方式整體都是比keySet方式要高一些,程式碼如下:
public static void main(String[] args) {
Map<Integer, String> map=new TreeMap<Integer, String>();
map.put(11, "張三");
map.put(22, "李四");
map.put(33, "王五");
map.put(11, "張三三");
for(Map.Entry<Integer, String> entry:map.entrySet()){
System.out.println("key:"+entry.getKey()+"\t"+"value:"+entry.getValue());
}
}
entrySet比keySet快的原因:
如果就只獲取key來說,兩者的差別並不大,但是如果要獲取value,還是entrySet的效率會更好。因為keySet需要從map中再次根據key獲取value(keySet相當於遍歷了2次),而entrySet是一次都全部獲取出來。
map.get(key)獲取的時候,底層其實根據key的hashcode值經過雜湊演算法得到一個hash值然後作為索引對映到對應table陣列的索引位置,這是一次密集型計算,很耗費CPU,如果有大量的元素,則會使CPU使用率飆升,影響響應速度,而entrySet()返回的set裡邊元素都是Map.Entry型別,key和value就是這個類的一個屬性,entry.getKey()和entry.getValue()效率肯定很高。
五、請說一說HashMap和HashSet有哪些區別?
HashMap | HashSet |
實現了Map介面 | 實現了Set介面 |
儲存鍵值對 | 只儲存物件 |
使用put()方法將元素放入map中 | 使用add()方法將元素放入set中 |
使用鍵物件來計算hashcode值 | HashSet使用成員物件來計算hashcode值,對於兩個物件來說hashcode可能相同,所以equals()方法用來判斷物件的相等性,如果兩個物件不同的話,那麼返回false。 |
HashMap比較快,因為是使用唯一的鍵來獲取物件 | HashSet較HashMap來說比較慢 |
六、HashSet、TreeSet、LinkedHashSet區別?
- HashSet:插入速度快
- TreeSet:可以確保集合元素處於排序狀態
- LinkedHashSet:可以按照插入的順序儲存集合
1.HashSet是基於Hash演算法實現的,其效能通常都優於TreeSet。為快速查詢而設計的Set,我們通常都應該使用HashSet,在我們需要排序的功能時,我們才使用TreeSet。
2.HashSet還有一個子類LinkedHashSet,LinkedHashSet集合也是根據元素hashCode值來決定元素儲存位置,但它同時使用連結串列維護元素的次序,當遍歷該集合時候,LinkedHashSet將會以元素的新增順序訪問集合的元素。 如果我們需要迭代遍歷的順序為插入順序或者訪問順序,那麼 LinkedHashSet 是需要我們首先考慮的。
七、HashMap的資料儲存和實現原理你瞭解多少?
HashMap中的資料結構是陣列+單鏈表的組合,以鍵值對(key-value)的形式儲存元素的,通過put()和get()方法儲存和獲取物件。可以理解為兩列多行的表格,第一列中儲存索引或者起標識作用的物件,第二列儲存我們實際要用的物件,當我們需要第二列中某個物件時,就去找這個物件的索引。
- 當我們給put()方法傳遞鍵和值時,HashMap會由key來呼叫hash()方法,返回鍵的hash值,計算Index後用於找到bucket(雜湊桶)的位置來儲存Entry物件。
- 我們呼叫get()方法,HashMap會使用key的hashcode找到bucket位置,因為HashMap在連結串列中儲存的是Entry鍵值對,所以找到bucket位置之後,會呼叫key的equals()方法,按順序遍歷連結串列的每個 Entry,直到找到想獲取的 Entry 為止。
八、在什麼場景下要重寫equals()和hashcode()方法?
1.將物件放到Set集合或者是想作為Map的key時,那麼你必須重寫equals()方法,這樣才能保證唯一性。hashCode 和 equals的關係:兩個物件 equals的時候,hashCode必須相等,但hashCode相等,物件不一定equals。
2.必須重寫hashCode()的情況:如果你的物件想放進雜湊儲存的集合中(比如:HashSet,LinkedHashSet)或者想作為雜湊Map(例如:HashMap,LinkedHashMap等等)的Key時,在重寫equals()方法的同時,必須重寫hashCode()方法。hashCode()方法存在的主要目的就是提高效率,但是如果你想把物件放到雜湊儲存結構的集合中時,是必須要重寫的。
hashCode並不能表現其唯一性,但是有離散性,其意義就是類似於進行hashMap等操作時,加快物件比較的速度,進而加快物件搜尋的速度。
九、HashMap和TreeMap有什麼不同?
1.當Map中插入、刪除和定位元素這類操作時,HashMap是最好的選擇。
2.如果你需要對一個有序的key集合進行遍歷,TreeMap是更好的選擇。基於你的collection的大小,向HashMap中新增元素會更快,將map換為TreeMap可以進行有序key的遍歷。
十、Collections和Collection有哪些區別?
Collection 是一個集合根介面,Collections 是一個包裝類(工具類/幫助類)。它包含有各種有關集合操作的靜態多型方法。此類不能例項化,就像一個工具類,用於對集合中元素進行排序、搜尋以及執行緒安全等各種操作,服務於Java的Collection框架。
十一、如何對一組物件進行排序?
- 如果我們需要對一個物件陣列進行排序,我們可以使用Arrays.sort()方法。
- 如果我們需要排序一個物件列表,我們可以使用Collection.sort()方法。
兩個都有用於自然排序(使用Comparable)或基於標準的排序(使用Comparator)的過載方法sort()。Collections內部使用陣列排序方法,所有它們兩者都有相同的效能,只是Collections需要花時間將列表轉換為陣列。
十二、Comparable和Comparator介面有何區別?
Comparable | 用來提供物件的自然排序,我們可以使用它來提供基於單個邏輯的排序。 |
Comparator | 提供不同的排序演算法,我們可以選擇需要使用的Comparator來對給定的物件集合進行排序。 |
Comparable和Comparator介面被用來對物件集合或者陣列進行排序。
--------------------------------------------------------保持專注,世界才會為你讓路。--------------------------------------------------------