JAVA面試題合集——精髓(一)

Hro發表於2018-11-22

1、hashcode相等兩個類一定相等嗎?equals呢?相反呢?

hashCode相等,equals也不一定相等, 兩個類也不一定相等。
原因:hashCode相同,可能是多個鍵,值相同而已,那麼equals也可能不相同;equal相等,那麼必定
是同一個物件,即hashcode必定相同
複製程式碼

2、介紹一下集合框架?

Java中的集合框架的實現是Java容器類相關類庫,容器類有兩種劃分:
  (1)、Collection介面:一個包含獨立元素的序列,序列的每一個位置都包含一個獨立的元素,
	且各個元素之間是無序的,是可重複的,是可以為null的。
	a、繼承了Collection介面的介面有:List、Queue、Set;
	b、繼承list介面的有:AbstractList 及LinkedList,常用的ArrayList繼承自AbstractList。
	    ArrayList是基於陣列實現的,其底層實現為一個長度動態增長的Object[]陣列,
	    因此其具有訪問快,增刪慢的特點。
	c、Queue 不允許隨機訪問其中間的元素,只能從隊首訪問的Collection,且一般來說佇列都
	    應該是FIFO(先進先出)的。
	d、Set是元素不重複的Collection。實現了Set介面的有HashSet、LinkedHashSet、
	    SortedSet介面繼承了Set介面。
	
  (2)、Map介面:一個每一組資料都是鍵值對的容器,並能夠通過其鍵來查詢其對應值;
	a、基於Map介面實現的類有很多,常用的有:TreeMap,HashMap,LinkedHashMap
	b、TreeMap儲存key-value對(節點)時,需要根據key對節點進行排序,
	可以保證所有的key-value對處於有序狀態
	c、HashMap用於快速訪問
	d、LinkedHashMap能夠保持元素插入的順序,也提供快速訪問的能力。
複製程式碼

3、hashmap hastable 底層實現什麼區別?hashtable和concurrenthashtable呢?

    (1)、HashTable:
	底層陣列+連結串列實現,無論key還是value都不能為null,
	執行緒安全,實現執行緒安全的方式是在修改資料時synchronized鎖住整個HashTable,效率低,
	初始size為11,擴容:newsize = olesize*2+1,
	出現hash衝突時採用的是將新元素加入到連結串列的開頭,
	定址方式採用的是求餘數:index = (hash & 0x7FFFFFFF) % tab.length
    (2)、HashMap:
	jdk1.8之前底層陣列+連結串列實現,1.8之後陣列+連結串列+紅黑樹結構
	可以儲存null鍵和null值,執行緒不安全
	初始size為16,擴容:newsize = oldsize*2,size一定為2的n次冪
	擴容針對整個Map,每次擴容時,原來陣列中的元素依次重新計算存放位置,並重新插入
	出現hash衝突時,如果連結串列節點數小於8時是將新元素加入到連結串列的末尾
	定址方法採用的是位運算按位與:index = hash & (tab.length – 1)
    (3)、Concurrenthashtable:
	(a)、jdk1.8之前採用Segment + HashEntry的方式進行實現,
	預設size為16,Segment在實現上繼承了ReentrantLock,自帶了鎖的功能。
	    PUT:
		當執行put操作時,會進行第一次key的hash來定位Segment的位置,
		如果該Segment還沒有初始化,即通過CAS操作進行賦值,
		然後進行第二次hash操作,找到相應的HashEntry的位置,
		這裡會利用繼承過來的鎖的特性,在將資料插入指定的HashEntry位置時(連結串列的尾端),
		會通過繼承ReentrantLock的tryLock()方法嘗試去獲取鎖,
		如果獲取成功就直接插入相應的位置,如果已經有執行緒獲取該Segment的鎖,
		那當前執行緒會以自旋的方式去繼續的呼叫tryLock()方法去獲取鎖,
		超過指定次數(在多處理器環境下,重複次數為64,單處理器重複次數為1)就掛起,
		等待喚醒。
	    SIZE:
		先採用不加鎖的方式,連續計算元素的個數,最多計算3次:
		如果前後兩次計算結果相同,則說明計算出來的元素個數是準確的;
		如果前後兩次計算結果都不同,則給每個Segment進行加鎖,再計算一次元素的個數;
	(b)、jdk1.8之後採用Node + CAS + Synchronized來保證併發安全進行實現。
	    PUT:
		1、如果沒有初始化就先呼叫initTable()方法來進行初始化過程
		2、如果沒有hash衝突就直接CAS插入
		3、如果還在進行擴容操作就先進行擴容
		4、如果存在hash衝突,就加鎖來保證執行緒安全,這裡有兩種情況,
			一種是連結串列形式就直接遍歷到尾端插入,
			一種是紅黑樹就按照紅黑樹結構插入
		5、最後一個如果該連結串列的數量大於閾值8,就要先轉換成黑紅樹的結構,
		    break再一次進入迴圈
		6、如果新增成功就呼叫addCount()方法統計size,並且檢查是否需要擴容
	    SIZE:
		使用一個volatile型別的變數baseCount記錄元素的個數,當插入新資料或則刪除數
		據時,會通過addCount()方法更新baseCount。
			
總結:1.7:
	Concurrenthashtable儲存結構陣列+連結串列,同步機制採用了”分段鎖”策略,
	將map分為N個segment,預設提升16倍,
	鍵值對為HashEntry,涉及到的共享變數都使用volatile修飾,volatile可以保證記憶體可見性	
      1.8:
	Concurrenthashtable儲存結構陣列+連結串列+紅黑樹,同步機制採用“CAS + synchronized”,
	鍵值對為Node,原始碼中,部分使用sychronizeded關鍵字控制,防止多個執行緒操作。複製程式碼

相關文章