亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

HashMap 的工作原理

zhisheng / 1473人閱讀

摘要:的工作原理是近年來常見的面試題。讓我們再來看看這些問題設(shè)計哪些知識點的概念中解決碰撞的方法和的應(yīng)用,以及它們在中的重要性不可變對象的好處多線程的條件競爭重新調(diào)整的大小總結(jié)的工作原理基于原理,我們通過和方法儲存和獲取對象。

HashMap 的工作原理是近年來常見的 Java 面試題。幾乎每個 Java 程序員都知道 HashMap,都知道哪里要用 HashMap,知道Hashtable和HashMap之間的區(qū)別,那么為何這道面試題如此特殊呢?是因為這道題考察的深度很深。這題經(jīng)常出現(xiàn)在高級或中高級面試中。投資銀行更喜歡問這個問題,甚至?xí)竽銓崿F(xiàn) HashMap 來考察你的編程能力。ConcurrentHashMap 和其它同步集合的引入讓這道題變得更加復(fù)雜。讓我們開始探索的旅程吧!

先來些簡單的問題

“你用過 HashMap 嗎?” “什么是 HashMap?你為什么用到它?”

幾乎每個人都會回答"是的”,然后回答 HashMap 的一些特性,譬如 HashMap 可以接受 null鍵值和值,而Hashtable則不能;HashMap 是非synchronized; HashMap 很快;以及HashMap 儲存的是鍵值對等等。這顯示出你已經(jīng)用過 HashMap ,而且對它相當(dāng)?shù)氖煜?。但是面試官來個急轉(zhuǎn)直下,從此刻開始問出一些刁鉆的問題,關(guān)于 HashMap 的更多基礎(chǔ)的細(xì)節(jié)。面試官可能會問出下面的問題:

“你知道 HashMap 的工作原理嗎?” “你知道 HashMap 的get()方法的工作原理嗎?”

你也許會回答“我沒有詳查標(biāo)準(zhǔn)的Java API,你可以看看Java源代碼或者Open JDK?!薄拔铱梢杂肎oogle找到答案?!?/p>

但一些面試者可能可以給出答案,“ HashMap 是基于hashing的原理,我們使用put(key, value)存儲對象到HashMap中,使用get(key)從 HashMap 中獲取對象。當(dāng)我們給put()方法傳遞鍵和值時,我們先對鍵調(diào)用hashCode()方法,返回的hashCode用于找到bucket位置來儲存Entry對象?!边@里關(guān)鍵點在于指出, HashMap 是在bucket中儲存鍵對象和值對象,作為Map.Entry。這一點有助于理解獲取對象的邏輯。如果你沒有意識到這一點,或者錯誤的認(rèn)為僅僅只在bucket中存儲值的話,你將不會回答如何從 HashMap 中獲取對象的邏輯。這個答案相當(dāng)?shù)恼_,也顯示出面試者確實知道hashing以及HashMap的工作原理。但是這僅僅是故事的開始,當(dāng)面試官加入一些Java程序員每天要碰到的實際場景的時候,錯誤的答案頻現(xiàn)。下個問題可能是關(guān)于HashMap中的碰撞探測(collision detection)以及碰撞的解決方法:

“當(dāng)兩個對象的hashcode相同會發(fā)生什么?” 從這里開始,真正的困惑開始了,一些面試者會回答因為hashcode相同,所以兩個對象是相等的,HashMap 將會拋出異常,或者不會存儲它們。然后面試官可能會提醒他們有 equals()hashCode()兩個方法,并告訴他們兩個對象就算hashcode相同,但是它們可能并不相等。一些面試者可能就此放棄,而另外一些還能繼續(xù)挺進(jìn),他們回答“因為 hashcode 相同,所以它們的bucket位置相同,‘碰撞’會發(fā)生。因為HashMap使用鏈表存儲對象,這個Entry(包含有鍵值對的Map.Entry對象)會存儲在鏈表中?!边@個答案非常的合理,雖然有很多種處理碰撞的方法,這種方法是最簡單的,也正是 HashMap 的處理方法。但故事還沒有完結(jié),面試官會繼續(xù)問:

“如果兩個鍵的hashcode相同,你如何獲取值對象?” 面試者會回答:當(dāng)我們調(diào)用get()方法,HashMap會使用鍵對象的hashcode找到bucket位置,然后獲取值對象。面試官提醒他如果有兩個值對象儲存在同一個bucket,他給出答案:將會遍歷鏈表直到找到值對象。面試官會問因為你并沒有值對象去比較,你是如何確定確定找到值對象的?除非面試者直到HashMap在鏈表中存儲的是鍵值對,否則他們不可能回答出這一題。

其中一些記得這個重要知識點的面試者會說,找到bucket位置之后,會調(diào)用keys.equals()方法去找到鏈表中正確的節(jié)點,最終找到要找的值對象。完美的答案!

許多情況下,面試者會在這個環(huán)節(jié)中出錯,因為他們混淆了hashCode()equals()方法。因為在此之前hashCode()屢屢出現(xiàn),而equals()方法僅僅在獲取值對象的時候才出現(xiàn)。一些優(yōu)秀的開發(fā)者會指出使用不可變的、聲明作final的對象,并且采用合適的equals()hashCode()方法的話,將會減少碰撞的發(fā)生,提高效率。不可變性使得能夠緩存不同鍵的hashcode,這將提高整個獲取對象的速度,使用String,Interger這樣的wrapper類作為鍵是非常好的選擇。

如果你認(rèn)為到這里已經(jīng)完結(jié)了,那么聽到下面這個問題的時候,你會大吃一驚。“如果HashMap的大小超過了負(fù)載因子(load factor)定義的容量,怎么辦?”除非你真正知道HashMap的工作原理,否則你將回答不出這道題。默認(rèn)的負(fù)載因子大小為0.75,也就是說,當(dāng)一個map填滿了75%的bucket時候,和其它集合類(如ArrayList等)一樣,將會創(chuàng)建原來HashMap大小的兩倍的bucket數(shù)組,來重新調(diào)整map的大小,并將原來的對象放入新的bucket數(shù)組中。這個過程叫作rehashing,因為它調(diào)用hash方法找到新的bucket位置。

如果你能夠回答這道問題,下面的問題來了:“你了解重新調(diào)整HashMap大小存在什么問題嗎?”你可能回答不上來,這時面試官會提醒你當(dāng)多線程的情況下,可能產(chǎn)生條件競爭(race condition)。

當(dāng)重新調(diào)整HashMap大小的時候,確實存在條件競爭,因為如果兩個線程都發(fā)現(xiàn)HashMap需要重新調(diào)整大小了,它們會同時試著調(diào)整大小。在調(diào)整大小的過程中,存儲在鏈表中的元素的次序會反過來,因為移動到新的bucket位置的時候,HashMap并不會將元素放在鏈表的尾部,而是放在頭部,這是為了避免尾部遍歷(tail traversing)。如果條件競爭發(fā)生了,那么就死循環(huán)了。這個時候,你可以質(zhì)問面試官,為什么這么奇怪,要在多線程的環(huán)境下使用HashMap呢?:)

熱心的讀者貢獻(xiàn)了更多的關(guān)于HashMap的問題:

為什么String, Interger這樣的wrapper類適合作為鍵? String, Interger這樣的wrapper類作為HashMap的鍵是再適合不過了,而且String最為常用。因為String是不可變的,也是final的,而且已經(jīng)重寫了equals()hashCode()方法了。其他的wrapper類也有這個特點。不可變性是必要的,因為為了要計算hashCode(),就要防止鍵值改變,如果鍵值在放入時和獲取時返回不同的hashcode的話,那么就不能從 HashMap中找到你想要的對象。不可變性還有其他的優(yōu)點如線程安全。如果你可以僅僅通過將某個field聲明成final就能保證hashCode是不變的,那么請這么做吧。因為獲取對象的時候要用到equals()hashCode()方法,那么鍵對象正確的重寫這兩個方法是非常重要的。如果兩個不相等的對象返回不同的hashcode的話,那么碰撞的幾率就會小些,這樣就能提高 HashMap 的性能。
我們可以使用自定義的對象作為鍵嗎? 這是前一個問題的延伸。當(dāng)然你可能使用任何對象作為鍵,只要它遵守了equals()hashCode()方法的定義規(guī)則,并且當(dāng)對象插入到Map中之后將不會再改變了。如果這個自定義對象時不可變的,那么它已經(jīng)滿足了作為鍵的條件,因為當(dāng)它創(chuàng)建之后就已經(jīng)不能改變了。
我們可以使用 CocurrentHashMap 來代替 Hashtable 嗎?這是另外一個很熱門的面試題,因為 ConcurrentHashMap 越來越多人用了。我們知道 Hashtable 是 synchronized的 ,但是ConcurrentHashMap 同步性能更好,因為它僅僅根據(jù)同步級別對map的一部分進(jìn)行上鎖。ConcurrentHashMap當(dāng)然可以代替HashTable,但是HashTable提供更強的線程安全性??纯催@篇博客查看Hashtable和ConcurrentHashMap的區(qū)別。
我個人很喜歡這個問題,因為這個問題的深度和廣度,也不直接的涉及到不同的概念。讓我們再來看看這些問題設(shè)計哪些知識點:

hashing的概念

HashMap中解決碰撞的方法

equals()和hashCode()的應(yīng)用,以及它們在HashMap中的重要性

不可變對象的好處

HashMap多線程的條件競爭

重新調(diào)整HashMap的大小
總結(jié)

HashMap的工作原理

HashMap基于hashing原理,我們通過put()和get()方法儲存和獲取對象。當(dāng)我們將鍵值對傳遞給put()方法時,它調(diào)用鍵對象的hashCode()方法來計算hashcode,讓后找到bucket位置來儲存值對象。當(dāng)獲取對象時,通過鍵對象的equals()方法找到正確的鍵值對,然后返回值對象。HashMap使用鏈表來解決碰撞問題,當(dāng)發(fā)生碰撞了,對象將會儲存在鏈表的下一個節(jié)點中。 HashMap在每個鏈表節(jié)點中儲存鍵值對對象。

當(dāng)兩個不同的鍵對象的hashcode相同時會發(fā)生什么? 它們會儲存在同一個bucket位置的鏈表中。鍵對象的equals()方法用來找到鍵值對。

因為HashMap的好處非常多,我曾經(jīng)在電子商務(wù)的應(yīng)用中使用HashMap作為緩存。因為金融領(lǐng)域非常多的運用Java,也出于性能的考慮,我們會經(jīng)常用到HashMap和ConcurrentHashMap。你可以查看更多的關(guān)于HashMap的文章:

HashMap和Hashtable的區(qū)別

HashMap和HashSet的區(qū)別


原文:How HashMap works in Java
轉(zhuǎn)載自:ImportNew.com - 唐小娟

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/64046.html

相關(guān)文章

  • 理解Java中HashMap工作原理

    摘要:中的使用散列來高效的查找和存儲值。理解中的方法是頂層對象中的方法因此中所有的對象都會帶有方法。中給出了覆蓋方法的最佳實踐把某個非零的常數(shù)值比如保存在一個名為的類型中。 Java中的HashMap使用散列來高效的查找和存儲值。HashMap內(nèi)部使用Map.Entry的形式來保存key和value,使用put(key,value)方法存儲值,使用get(key)方法查找值。 理解hashC...

    xiangchaobin 評論0 收藏0
  • HashMap實現(xiàn)原理筆記

    摘要:掌握的實現(xiàn)原理,已經(jīng)是程序員的基礎(chǔ)操作了。后記這次主要是理解了一下的實現(xiàn)原理,特別重點寫了很多關(guān)于散列函數(shù)的理解,并沒有按照源碼一行行的去理解。之前看的時候?qū)ι⒘泻瘮?shù)都是跳過去的,只知道是用來計算鍵的,不知道里面的原理。 序 HashMap是Java中常用的Map接口的實現(xiàn)類,因為在日常工作中非常頻繁的出現(xiàn),所以在大部分的Java面試中都會問幾個關(guān)于HashMap的問題。掌握HashM...

    _DangJin 評論0 收藏0
  • HashMap 精講原理

    摘要:從結(jié)構(gòu)實現(xiàn)來講,是數(shù)組鏈表紅黑樹增加了紅黑樹部分實現(xiàn)的。當(dāng)鏈表長度大于時,將這個鏈表轉(zhuǎn)換成紅黑樹,利用紅黑樹快速增刪改查的特點提高的性能。 原文鏈接 更多教程 本文涉及HashMap的: HashMap的簡單使用 HashMap的存儲結(jié)構(gòu)原理 HashMap的擴容方法原理 HashMap中定位數(shù)據(jù)索引實現(xiàn) HashMap中put、get方法實現(xiàn) HashMap的簡單使用 Ha...

    Lyux 評論0 收藏0
  • Java 集合總結(jié)(Collection系列與Map系列)

    摘要:前言原文在點這里,這也是作者的個人網(wǎng)站,希望多多支持,對于作者而言,集合主要分為兩個派系,一個是系列,一個是系列。的線程安全版本,內(nèi)部的實現(xiàn)幾乎和一模一樣。也是的線程安全版本,并且使用了分段加鎖機制,所以效率上要比要好很多。 前言 原文在: 點這里,這也是作者的個人網(wǎng)站,希望多多支持,O(∩_∩)O~ 對于作者而言,Java 集合主要分為兩個派系,一個是 Collection 系列,一...

    zhou_you 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<