1. 程式人生 > >HashMap面試所需知識

HashMap面試所需知識

實現

通過put和get儲存和獲取物件,儲存物件時,我們將K/V傳給put方法時,它呼叫hashcode計算hash從而得到bucket位置,進一步儲存,HashMap會根據當前bucket的佔用情況自動調整容量。獲取物件時,我們將K傳遞給get,他呼叫hashcode計算hash從而得到bucket位置,並進一步呼叫equals()方法確認鍵值對。

 

HashMap的幾個重要的資訊:

預設大小為16( 2 的4次方)

擴容機制:當目前數超過總數的75%時擴充套件,擴充套件為原來的2倍,也就是2的n+1次方。

最大存2的30次方,在空間大於8的時候會變成紅黑樹的資料結構,當又小於6的時候又會變回連結串列

 

List、Set、Map之間的區別?

List和Set都繼承Collection,但是Map不是Collection的子介面。

List 可以允許重複的元素  可以插入多個null元素  有序的容器,插入的順序和輸出的順序一樣      

Set 不允許重複元素  只允許一個null元素 無序容器

Map 鍵值對儲存,鍵必須唯一,但是值可以重複  鍵只允許一個null,值可以允許有多個null   無序容器

 

HashMap集合知識:

  1.   關於HashMap的一些說法: 
  1.   HashMap實際上是一個“連結串列雜湊”的資料結構,即陣列和連結串列的結合體。HashMap的底層結構是一個數組,陣列中的每一項是一條連結串列。 
  2.   HashMap的例項有倆個引數影響其效能: “初始容量” 和 裝填因子。 
  3.   HashMap實現不同步,執行緒不安全。  HashTable執行緒安全 
  4.   HashMap中的key-value都是儲存在Entry中的。
  5.   HashMap可以存null鍵和null值,不保證元素的順序恆久不變,它的底層使用的是陣列和連結串列,通過hashCode()方法和equals方法保證鍵的唯一性
  6.   解決衝突主要有三種方法:定址法,拉鍊法,再雜湊法。HashMap是採用拉鍊法解決雜湊衝突的。 注: 連結串列法是將相同hash值的物件組成一個連結串列放在hash值對應的槽位;    用開放定址法解決衝突的做法是:當衝突發生時,使用某種探查(亦稱探測)技術在散列表中形成一個探查(測)序列。 沿此序列逐個單元地查詢,直到找到給定 的關鍵字,或者碰到一個開放的地址(即該地址單元為空)為止(若要插入,在探查到開放的地址,則可將待插入的新結點存人該地址單元)。   

拉鍊法解決衝突的做法是: 將所有關鍵字為同義詞的結點連結在同一個單鏈表中 。若選定的散列表長度為m,則可將散列表定義為一個由m個頭指標組成的指標數 組T[0..m-1]。凡是雜湊地址為i的結點,均插入到以T[i]為頭指標的單鏈表中。T中各分量的初值均應為空指標。在拉鍊法中,裝填因子α可以大於1,但一般均取α≤1。拉鍊法適合未規定元素的大小。   

 

 

Hashtable和HashMap的區別: 

a)   繼承不同。  public class Hashtable extends Dictionary implements Map 

public class HashMap extends  AbstractMap implements Map .

b)  Hashtable中的方法是同步的,而HashMap中的方法在預設情況下是非同步的。在多執行緒併發的環境下,可以直接使用Hashtable,但是要使用HashMap的話就要自己增加同步處理了。

 c)  Hashtable 中, key 和 value 都不允許出現 null 值。 在 HashMap 中, null 可以作為鍵,這樣的鍵只有一個;可以有一個或多個鍵所對應的值為 null 。當 get() 方法返回 null 值時,即可以表示 HashMap 中沒有該鍵,也可以表示該鍵所對應的值為 null 。因此,在 HashMap 中不能由 get() 方法來判斷 HashMap 中是否存在某個鍵, 而應該用 containsKey() 方法來判斷。 

d)  兩個遍歷方式的內部實現上不同。Hashtable、HashMap都使用了Iterator。而由於歷史原因,Hashtable還使用了Enumeration的方式 。 

e)  雜湊值的使用不同,HashTable直接使用物件的hashCode。而HashMap重新計算hash值。 

f)  Hashtable和HashMap它們兩個內部實現方式的陣列的初始大小和擴容的方式。HashTable中hash陣列預設大小是11,增加的方式是old*2+1。HashMap中hash陣列的預設大小是16,而且一定是2的指數。   注:  HashSet子類依靠hashCode()和equal()方法來區分重複元素。      HashSet內部使用Map儲存資料,即將HashSet的資料作為Map的key值儲存,這也是HashSet中元素不能重複的原因。而Map中儲存key值的,會去判斷當前Map中是否含有該Key物件,內部是先通過key的hashCode,確定有相同的hashCode之後,再通過equals方法判斷是否相同。 

 

如果兩個鍵的hashcode相同,你如何獲取值物件?

當我們呼叫get()方法,HashMap會使用鍵物件的hashcode找到bucket位置,然後獲取值物件。如果有兩個值物件儲存在同一個bucket,將會遍歷LinkedList直到找到值物件。找到bucket位置之後,會呼叫keys.equals()方法去找到LinkedList中正確的節點,最終找到要找的值物件。(當程式通過 key 取出對應 value 時,系統只要先計算出該 key 的 hashCode() 返回值,在根據該 hashCode 返回值找出該 key 在 table 陣列中的索引,然後取出該索引處的 Entry,最後返回該 key 對應的 value 即可。)

 

在多執行緒的情況下,當重新調整HashMap大小的時候,就會存在條件競爭,因為如果兩個執行緒都發現HashMap需要重新調整大小了,它們會同時試著調整大小。在調整大小的過程中,儲存在連結串列中的元素的次序會反過來,因為移動到新的bucket位置的時候,HashMap並不會將元素放在連結串列的尾部,而是放在頭部,這是為了避免尾部遍歷。如果條件競爭發生了,那麼就會產生死迴圈了。

 

內容選自:https://blog.csdn.net/mbshqqb/article/details/79799009  

https://blog.csdn.net/brycegao321/article/details/52527236