51.HashMap的實現原理java
HashMap的主幹是一個Entry數組。 Entry是HashMap的基本組成單元, 每個Entry包含一個key-value鍵值對。 HashMap基於hashing原理, 咱們經過put()和get()方法儲存和獲取對象。 當咱們將鍵值對傳遞給put()方法時, 它調用鍵對象的hashCode()方法 來計算hashcode, 讓後找到bucket位置來儲存值對象。 當獲取對象時, 經過鍵對象的equals()方法 找到正確的鍵值對, 而後返回值對象。 HashMap使用鏈表來解決碰撞問題, 當發生碰撞了, 對象將會儲存在鏈表的下一個節點中。 HashMap在每一個鏈表節點中儲存鍵值對對象。 當兩個不一樣的鍵對象的hashcode 相同時會發生什麼? 它們會儲存在同一個bucket位置的鏈表中。 鍵對象的equals()方法用來找到鍵值對。 由於HashMap的好處很是多, 我曾經在電子商務的應用中使用HashMap做爲緩存。 由於金融領域很是多的運用Java, 也出於性能的考慮, 咱們會常常用到HashMap和ConcurrentHashMap。 HashMap由數組+鏈表組成的, 數組是HashMap的主體, 鏈表則是主要爲了解決哈希衝突而存在的, 若是定位到的數組位置不含鏈表 當前entry的next指向null, 那麼對於查找, 添加等操做很快, 僅需一次尋址便可; 若是定位到的數組包含鏈表, 對於添加操做, 其時間複雜度爲O(n), 首先遍歷鏈表, 存在即覆蓋, 不然新增; 對於查找操做來說, 仍需遍歷鏈表, 而後經過key對象的equals方法逐一比對查找。 因此,性能考慮,HashMap中的鏈表出現越少, 性能纔會越好。
52.List、Set、Map之間的區別web
List、Set是實現了Collection接口的子接口; 而Map是另外一個集合接口。 1元素重複性: List容許有重複的元素。 任何數量的重複元素 均可以在不影響現有重複元素的值 及其索引的狀況下插入到List集合中; Set集合不容許元素重複。 Set以及全部實現了Set接口的類 都不容許重複值的插入, 若屢次插入同一個元素時, 在該集合中只顯示一個; Map以鍵值對的形式對元素進行存儲。 Map不容許有重複鍵, 但容許有不一樣鍵對應的重複的值; 2.元素的有序性: List及其全部實現類保持了 每一個元素的插入順序; Set中的元素都是無序的; 可是某些Set的實現類 以某種殊形式對其中的元素進行排序, 如:LinkedHashSet按照元素的 插入順序進行排序; Map跟Set同樣對元素進行無序存儲, 但其某些實現類對元素進行了排序。 如:TreeMap根據鍵對其中的元素進行升序排序; 3.元素是否爲空值: 1.List容許任意數量的空值; 2.Set最多容許一個空值的出現; 當向Set集合中添加多個null值時, 在該Set集合中只會顯示一個null元素 3.Map只容許出現一個空鍵, 但容許出現任意數量的空值; --------------------------------- 總結: List中的元素: 有序、可重複、可爲空; Set中的元素: 無序、不重複、只有一個空元素; Map中的元素: 無序、鍵不重,值可重、可一個空鍵、多可空值;
53.HashMap 的長度爲何是2的冪次方算法
1.減少哈希衝突機率 假如當前Entry數組長度爲len, 插入節點時, 須要對key的hashcode進行二次哈希, 而後跟len-1相與 獲得的值必定小於len,避免數組越界 若是len是2的N次方, 那麼len-1的後N位二進制必定是全1 假設有兩個key, 他們的hashcode不一樣, 分別爲code1和code2 code1和code2分別與一個後N位全1的二進制相與, 結果必定也不一樣 可是,若是code1和code2分別 與一個後N位非全1的二進制相與, 結果有可能相同 也就是說, 若是len是2^N, 不一樣hashcode的key 計算出來的數組下標必定不一樣; 不然, 不一樣hashcode的key 計算出來的數組下標必定相同。 因此HashMap長度爲全1, 能夠減少哈希衝突機率。 ---------------------- 2.提升計算下標的效率 若是len的二進制後n位非全1, 與len-1相與時, 0與1相與須要取反。 若是len的二進制後n位全1, 徹底不須要取反。 若是len爲2^N, 那麼與len-1相與, 跟取餘len等價, 而與運算效率高於取餘。 若是len不是2^N, 與len-1相與, 跟取餘len不等價。
54.集合框架中的泛型有什麼優勢?編程
首先, 瞭解一下Java關於泛型的概念。 泛型,在C++中被稱爲模板, 就是一種抽象的編程方式。 當咱們定義類和方法的時候, 能夠用一種通用的方式進行定義, 而沒必要寫出具體的類, 這些未知的東西會在真正使用的時候在肯定。 對於集合類來講, 它們能夠存放各類類型的元素。 若是在存放以前, 就能肯定元素的類型, 那麼就能夠更加直觀, 也讓代碼更加簡潔。 說明: java的泛型是停留在編譯層的, 也就是說JVM在對待泛型數據的時候, 依然會把它們當作是Object類型, 只不過在使用這些元素的時候, JVM會自動幫助咱們進行相應的類型轉換。 總結: 集合使用泛型以後, 能夠達到元素類型明確的目的, 避免了手動類型轉換的過程, 同時,也讓咱們更加明確 容器保存的是什麼類型的數據。
55.咱們可否使用任何類做爲Map的key?數組
一、能夠 可是作爲key的數據有以下要求: 二、首先, 要求明確一點Map集合存儲數據的 主要目的是爲了查找 而List集合是爲了輸出 三、既然是查找那麼就要涉及到對象比較 咱們說了若是要進行對象比較 就必須覆寫Object類中的equals()、hasCode() 至少覆寫equals()方法 簡單理解: 本身定義的類若是要想實現對象比較 就必須至少覆寫equals()方法 四、或則這麼說只要是本身定義的類 要想將其做爲key 就必須覆寫equals()方法 五、實際工做中 key的類型必定是String型 (95%通用) 其他的5%是沒事找事的 六、按標準開發、你會感到事半功倍, 不要沒事給本身找事, 固然求知精神是值得確定的。
56.Map接口提供了哪些不一樣的集合視圖?緩存
Map接口提供了三個集合視圖: 1.Set keyset(): 返回map中包含的全部key的一個Set視圖。 集合是受map支持的, map的變化會在集合中反映出來, 反之亦然。 當一個迭代器正在遍歷一個集合時, 若map被修改了(除迭代器自身的移除操做之外), 迭代器的結果會變爲未定義。 集合支持經過 Iterator的Remove、 Set.remove、 removeAll、 retainAll和clear操做進行元素移除, 從map中移除對應的映射。 它不支持add和addAll操做。 2.Collection values(): 返回一個map中包含的 全部value的一個Collection視圖。 這個collection受map支持的, map的變化會在collection中反映出來, 反之亦然。 當一個迭代器正在遍歷一個collection時, 若map被修改了(除迭代器自身的移除操做之外), 迭代器的結果會變爲未定義。 集合支持經過 Iterator的Remove、 Set.remove、 removeAll、 retainAll和clear操做進行元素移除, 從map中移除對應的映射。 它不支持add和addAll操做。 3.Set> entrySet(): 返回一個map鍾包含的 全部映射的一個集合視圖。 這個集合受map支持的, map的變化會在collection中反映出來, 反之亦然。 當一個迭代器正在遍歷一個集合時, 若map被修改了 除迭代器自身的移除操做, 以及對迭代器返回的entry進行setValue外, 迭代器的結果會變爲未定義。 集合支持經過 Iterator的Remove、 Set.remove、 removeAll、 retainAll和clear操做進行元素移除, 從map中移除對應的映射。 它不支持add和addAll操做。
57.哪些集合類是線程安全的?安全
在集合框架中,有些類是線程安全的, 這些都是jdk1.1中的出現的。 在jdk1.2以後, 就出現許許多多非線程安全的類。 下面是這些線程安全的同步的類: vector: 就比arraylist多了個同步化機制(線程安全), 由於效率較低, 如今已經不太建議使用。 在web應用中, 特別是前臺頁面, 每每效率(頁面響應速度)是優先考慮的。 statck:堆棧類,先進後出 hashtable:就比hashmap多了個線程安全 enumeration:枚舉,至關於迭代器 除了這些以外, 其餘的都是非線程安全的類和接口。 線程安全的類其方法是同步的, 每次只能一個訪問。 是重量級對象, 效率較低。
58.隊列和棧是什麼,列出它們的區別?數據結構
隊列(Queue): 是限定只能在表的一端進行 插入和在另外一端進行刪除操做的線性表; 棧(Stack): 是限定只能在表的一端 進行插入和刪除操做的線性表。 區別以下: 1、規則不一樣 1. 隊列:先進先出(First In First Out)FIFO 2. 棧:先進後出(First In Last Out )FILO 2、對插入和刪除操做的限定不一樣 1. 隊列:只能在表的一端進行插入, 並在表的另外一端進行刪除; 2. 棧:只能在表的一端插入和刪除。 3、遍歷數據速度不一樣 1. 隊列:基於地址指針進行遍歷, 並且能夠從頭部或者尾部進行遍歷, 但不能同時遍歷, 無需開闢空間, 由於在遍歷的過程當中不影響數據結構, 因此遍歷速度要快; 2. 棧:只能從頂部取數據, 也就是說最早進入棧底的, 須要遍歷整個棧才能取出來, 並且在遍歷數據的同時須要 爲數據開闢臨時空間, 保持數據在遍歷前的一致性。
59.哪個List實現了最快插入?併發
LinkedList和ArrayList 是另個不一樣變量列表的實現。 ArrayList的優點在於動態的增加數組, 很是適合初始時總長度未知的狀況下使用。 LinkedList的優點在於在中間位置插入和刪除操做, 速度是最快的。 LinkedList實現了List接口, 容許null元素。 此外LinkedList提供額外的 get,remove,insert方法 在LinkedList的首部或尾部。 這些操做使LinkedList可被 用做堆棧(stack), 隊列(queue) 或雙向隊列(deque)。 ArrayList實現了可變大小的數組。 它容許全部元素, 包括null。 每一個ArrayList實例都有一個容量(Capacity), 即用於存儲元素的數組的大小。 這個容量可隨着不斷添加新元素而自動增長, 可是增加算法並無定義。 當須要插入大量元素時, 在插入前能夠調用ensureCapacity方法來 增長ArrayList的容量以提升插入效率。
60.何時使用ConcurrentHashMap?框架
快速失敗的Java迭代器 可能會引起ConcurrentModifcationException 在底層集合迭代過程當中被修改。 故障安全做爲發生在實例中的一個副本 迭代是不會拋出任何異常的。 快速失敗的故障安全範例定義了 當遭遇故障時系統是如何反應的。 例如,用於失敗的快速迭代器ArrayList 和用於故障安全的迭代器ConcurrentHashMap。 ConcurrentHashMap被做爲 故障安全迭代器的一個實例, 它容許完整的併發檢索和更新。 當有大量的併發更新時, ConcurrentHashMap此時能夠被使用。 這很是相似於Hashtable, 但ConcurrentHashMap不鎖定 整個表來提供併發, 因此從這點上ConcurrentHashMap的性能 彷佛更好一些。 因此當有大量更新時 ConcurrentHashMap應該被使用。