日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

java异或_JAVA面试必备之HashMap必会点

發(fā)布時(shí)間:2023/12/10 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java异或_JAVA面试必备之HashMap必会点 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

今天我們就面試會(huì)問(wèn)到關(guān)于HashMap的問(wèn)題進(jìn)行一個(gè)匯總,以及對(duì)這些問(wèn)題進(jìn)行解答。

1、HashMap的數(shù)據(jù)結(jié)構(gòu)是什么?

2、為啥是線程不安全的?

3、Hash算法是怎樣實(shí)現(xiàn)的?

4、HashMap是如何處理Hash碰撞的?

5、增加元素的方法是怎么實(shí)現(xiàn)的?

6、獲取元素的方法時(shí)怎么實(shí)現(xiàn)的?

以上這些問(wèn)題在面試中出現(xiàn)的頻率往往比較高,在對(duì)HashMap不太了解的情況下,往往很難將這些問(wèn)題答全,筆者就帶領(lǐng)對(duì)這塊不熟悉的小伙伴們一起,一步一步解析以上的問(wèn)題。

1、HashMap的數(shù)據(jù)結(jié)構(gòu)是什么?

對(duì)于這個(gè)問(wèn)題,筆者建議回答的時(shí)候?qū)AVA版本進(jìn)行區(qū)分,因?yàn)椴煌姹鞠?#xff0c;HashMap的結(jié)構(gòu)是有些差異的。

回答:在JDK1.8之前HashMap是數(shù)組+鏈表的形式,JDK1.8包括之后是數(shù)組+鏈表+紅黑樹(shù)。本文講的HashMap是基于JDK1.8。

2、為啥是線程不安全的?

多個(gè)線程某個(gè)時(shí)刻同時(shí)操作HashMap并執(zhí)行put操作,且Hash值相同,這個(gè)時(shí)候需要解決沖突。很多方法如put() 、addEntry() 、resize() 等都不是同步的。

3、Hash算法是如何實(shí)現(xiàn)的?

"^"為異或符號(hào)其計(jì)算機(jī)符號(hào)為xor,相同為0,相異為1,如0^0=0 、0^1=1.">>>"為右移動(dòng)符號(hào),左側(cè)補(bǔ)零。圖中h>>>16就是將h的高16位換到h的低16位,而之前的高16位全補(bǔ)零。

這里有童鞋可能就會(huì)問(wèn)了,為什么要進(jìn)行這個(gè)向右移16位且異或的操作?

4、HashMap是如何處理Hash碰撞的?

HashMap采用的是鏈表法,將hash值相同的元素放在一個(gè)鏈表下。

5、增加元素的方法是怎么實(shí)現(xiàn)的?

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {Node<K,V>[] tab; Node<K,V> p; int n, i;// 如果說(shuō)桶(也就是數(shù)組,以下都用"桶"代替)為空,或者桶大小為0 則進(jìn)行初始化// 這里要區(qū)桶大小 和 桶內(nèi)元素的大小 桶大小是指桶裝東西的能力// 桶內(nèi)元素大小 是指桶裝了多少東西 if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;// 這里是幫助元素查找元素在桶中的定位 如果定位的位置沒(méi)有元素 那么// 直接將元素放入桶的該位置就行 if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);else {// 運(yùn)行到這說(shuō)明定位的位置已經(jīng)有元素了Node<K,V> e; K k;// 既然有人霸占元素的位置,那么就要與該元素進(jìn)行對(duì)比,看看自己的Hash值和// key值是不是和該位置的元素一直,如果都一直就記錄下該元素以下為e// 說(shuō)明有一個(gè)和我插入元素的key一樣的元素 后續(xù)可能要用新值替換舊值if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))e = p;// 如果只是Hash值相等而key不等,這里就是Hash碰撞啦,要解決hash碰撞// hashMap采用的是鏈地址法 就是碰撞的元素連成一個(gè)鏈表 這里由于鏈表// 如果太長(zhǎng)就會(huì)樹(shù)化成紅黑樹(shù),以下是判斷p也就是桶里放的是不是紅黑樹(shù)else if (p instanceof TreeNode)// 是紅黑樹(shù) 我們就把節(jié)點(diǎn)放入紅黑樹(shù) 注意:這里也不是一定插入到樹(shù)中,// 因?yàn)槿绻覀円迦氲脑睾图t黑樹(shù)中某個(gè)節(jié)點(diǎn)的key相同的話,也會(huì)考慮// 新值換舊值的問(wèn)題e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);else {// 跳到這 說(shuō)明p不是樹(shù),而是鏈表 binCount用來(lái)記錄鏈表中元素的個(gè)數(shù),那么// 為啥要記錄鏈表中元素的個(gè)數(shù)呢?主要判斷鏈表是否需要樹(shù)化成紅黑樹(shù)for (int binCount = 0; ; ++binCount) {// e的后一個(gè)節(jié)點(diǎn)為空 那么直接掛上我們要插入的元素if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);// TREEIFY_THRESHOLD 是樹(shù)化的閾值且其值為8// 這里要注意:我們要插入的節(jié)點(diǎn)p是還沒(méi)有加到binCount中的// 也就是說(shuō)這里雖然binCount>=7就可以樹(shù)化,其實(shí)真正的樹(shù)化// 條件是鏈表中元素個(gè)數(shù)大于等于8if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1sttreeifyBin(tab, hash);break;}// 待插入的key在鏈表中找到了,記錄下來(lái)然后退出if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}// 說(shuō)明找到了key相同的元素if (e != null) { // existing mapping for keyV oldValue = e.value;// 判斷是否需要舊值換新值,默認(rèn)情況下是允許更換的if (!onlyIfAbsent || oldValue == null)e.value = value;// 這個(gè)方法點(diǎn)進(jìn)去就是個(gè)空方法,主要是為了給繼承HashMap的// LinkedHashMap服務(wù)的afterNodeAccess(e);return oldValue;}}// 修改次數(shù)+1++modCount;// 看下達(dá)到擴(kuò)容的閥值沒(méi)if (++size > threshold)// 擴(kuò)容 ,在本方法的前面需要初始化的時(shí)候也出現(xiàn)過(guò)resize();// 這個(gè)方法同樣也是為L(zhǎng)inkedHashMap服務(wù)的afterNodeInsertion(evict);// 沒(méi)找到元素 就返回空return null;}

6、獲取元素的方法時(shí)怎么實(shí)現(xiàn)的?

使用hash值去找桶的位置:

final Node<K,V> getNode(int hash, Object key) {Node<K,V>[] tab; Node<K,V> first, e; int n; K k;// 桶不為空 并且桶的元素大于0 同時(shí)定位的位置元素還不為空 那就順藤摸瓜if ((tab = table) != null && (n = tab.length) > 0 &&(first = tab[(n - 1) & hash]) != null) {// 第一個(gè)元素是不是我們要找的啊?判斷一下,是就返回if (first.hash == hash && // always check first node((k = first.key) == key || (key != null && key.equals(k))))return first;if ((e = first.next) != null) {// 第一個(gè)元素不是我們要找的,而且后面還接著元素 判斷一下是不是樹(shù)if (first instanceof TreeNode)// 是樹(shù) 按照樹(shù)的獲取節(jié)點(diǎn)方法去獲取return ((TreeNode<K,V>)first).getTreeNode(hash, key);// 到這說(shuō)明是鏈表了 那就按照鏈表的方式去循環(huán)do {if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))return e;} while ((e = e.next) != null);}}return null;}

7、最后插播一下HashMap中的屬性

// 初始容量1向左移動(dòng)4位為16static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16// 最大容量1向左移30位static final int MAXIMUM_CAPACITY = 1 << 30;// 加載因子 也就是桶大小使用要是超過(guò)0.75 那么就要考慮擴(kuò)容了static final float DEFAULT_LOAD_FACTOR = 0.75f; // 鏈表太長(zhǎng) 要變樹(shù)的閥值static final int TREEIFY_THRESHOLD = 8;// 樹(shù)變成鏈表的閥值static final int UNTREEIFY_THRESHOLD = 6;// TREEIFY_THRESHOLD達(dá)到8也不一定樹(shù)化,還要容量達(dá)到64static final int MIN_TREEIFY_CAPACITY = 64;

下一期我們對(duì)今天講的put、get方法內(nèi)涉及到的重要的方法進(jìn)行講解。拜了個(gè)拜!

大量面試經(jīng)驗(yàn)以及學(xué)習(xí)資料書(shū)籍請(qǐng)關(guān)注微信公眾號(hào):AVAJ

回復(fù)"offer"進(jìn)行獲取

365篇大廠java面經(jīng) 你想要的我這里都有

總結(jié)

以上是生活随笔為你收集整理的java异或_JAVA面试必备之HashMap必会点的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。