String的hashCode方法不能濫用

2020-12-12 程式設計師生活

最近有小夥伴在使用java1.6的jdk時,發現1.6版本switch ..case 不支持字符串類型。

首先,升級jdk版本是不可能的,比較老項目,只能用1.6的。

比如下面這樣寫,jdk1.6不支持。

於是有個小夥伴說,這樣寫不就可以了?

的確,這樣寫是可以的,但並不建議。

首先,需要理解一下hashCode方法的含義,以及知道不同String,調用hashCode方法返回的值可能是相同的,比如"Aa"和"BB"的hashCode方法返回的都是2112.這時如果用在這裡,就有問題了。

我們再來看看String的hashCode方法源碼:

1、為什麼有個常數31作為生成hashCode算法的一部分?

大家都知道,計算機的乘法涉及到移位計算。當一個數乘以2時,就直接拿該數左移一位即可!選擇31原因是因為31是一個質數!

所謂質數是指在一個大於1的自然數中,除了1和此整數自身外,沒法被其他自然數整除的數。在存儲數據計算hash地址的時候,我們希望儘量減少有同樣的hash地址,所謂「衝突」。如果使用相同hash地址的數據過多,那麼這些數據所組成的hash鏈就更長,從而降低了查詢效率!

所以在選擇係數的時候要選擇儘量長(31 = 11111[2])的係數並且讓乘法儘量不要溢出(如果選擇大於11111的數,很容易溢出)的係數,因為如果計算出來的hash地址越大,所謂的「衝突」就越少,查找起來效率也會提高。

31的乘法可以由i*31== (i<<5)-1來表示,現在很多虛擬機裡面都有做相關優化,使用31的原因可能是為了更好的分配hash地址,並且31隻佔用5bits!在java乘法中如果數字相乘過大會導致溢出的問題,從而導致數據的丟失. 而31則是素數(質數)而且不是很長的數字,最終它被選擇為相乘的係數。

2、我們再來看看val[i]其實就是字符串裡的字符,當與整數相加時,會轉換成一個整數。

對於字符串"Aa",hash = 0+65 + 31*65 + 97 = 2112

對於欄位串"BB",hash = 0+66 + 31*66 +66 = 2112;

所以不同的字符有可能生成相同的hashCode,在swicht..case裡使用hashCode的寫法,是不建議的。

當然,當字符比較長時,衝突的概率是比較低的。

相關焦點

  • java中雙等號和equals的區別,重寫equals時要重寫hashcode
    如果我們想比較內容的話就需要在Student類裡面重寫equals方法和hashcode方法,這兩個方法是屬於Object裡面的方法,任何類都隱式的繼承了Object類。那為什麼非得重寫hashcode呢?因為對象的比較有硬性規定:應用執行期間,同一個對象內容不發生改變,經過多次調用,hashCode方法都必須始終返回同一個值。
  • Java中重寫equals方法為什麼要重寫hashcode方法?
    ==不能實現比較對象的值是否相同。所有對象都有equals方法,默認是Object類的equals,其結果與==一樣。如果希望比較對象的值相同,必須重寫equals方法。當equals方法被重寫時,通常有必要重寫hashCode方法,以維護hashCode方法的常規約定:值相同的對象必須有相同的hashCode。
  • 不懂得hashcode的重要性,程序的性能會大打折扣
    第二種:自己重寫equals和hashcode,這就不一定了。這得看你自己怎麼寫hashcode了。如果不滿足這2點,相同的對象可以出現在Set集合中,同時增加新元素的效率會大大下降(對於使用哈希存儲的系統,如果哈希碼頻繁的衝突將會造成存取性能急劇下降)規則說完,就說下為什麼hashcode會影響性能吧(重點,面試目的就是問他)大家都知道hashCode()方法給對象返回一個
  • Java為什麼重寫equals一定要重寫hashCode?
    初步探索首先我們要了解equals方法是什麼,hashcode方法是什麼。hashCode方法hashCode方法是本地方法,用於計算出對象的一個散列值,用於判斷在集合中對象是否重複的關鍵。一條定理equals相同的對象,hashCode必然相同。
  • 「原創」不重寫equals和hashcode難道就不行嗎?
    本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫究竟為什麼要重寫equals和hashcode???Java語言中,Object對象有個特殊的方法:hashcode()。public native int hashCode();是本地方法,有興趣的讀者可以深入了解一下。
  • 全網把Map中的hash()分析的最透徹的文章,別無二家。
    你知道為什麼JDK 7和JDK 8中hash方法實現的不同以及區別嗎?如果你不能很好的回答這些問題,那麼你需要好好看看這篇文章。文中涉及到大量代碼和計算機底層原理知識。絕對的乾貨滿滿。整個網際網路,把hash()分析的如此透徹的,別無二家了。
  • Java:hashCode()和equals()的contains,Set方法的協定
    本文是關於hashCode的,它等於Set中用於contains(Object o)方法的協定。但是,為什麼在使用contains()方法時沒有白狗呢?Set的contains(Object o)方法從Java Doc中,若且唯若此集合包含元素e使得(o == null?e == null:o.equals(e))時,contains()方法返回true。
  • Java String 對象,你真的了解了嗎?|CSDN 博文精選
    */privatefinal char value[];/** Cache the hash code for the string */private int hash; // Default to 0/** use serialVersionUID
  • java基礎入門-day18-equals()和hashCode()
    1 euqals()方法我們以Person類為例:public boolean equals(Object o)l 如果當前對象與o指向同一實例,那麼直接返回trueif(this == o) return true;
  • 工具:C 程序轉換ShellCode利器
    更易於擴展:指能夠執行shellcode的方法都可以使用Donut,基於Donut的二次開發也很容易。.程序中判斷CLR注入的方法:如果進程加載了CLR,但程序不是.NET程序集,則CLR已注入其中。.程序中判斷進程加載CLR的方法:進程是否加載了與CLR相關的dll(mscoree.dll,mscoreei.dll和mscorlib.dll),dll以"msco"開頭。
  • 一日一技:Python中的string.index()方法
    python學習string.index()方法index()方法返回字符串內子字符串的索引(如果找到)。 如果未找到子字符串,則會引發異常。string.index()的語法str.index(sub[, start[, end]] )index()參數index()方法採用三個參數:sub-要在字符串str中搜索的子字符串。
  • 一日一技:Python中的string.rindex()方法
    python學習string.rindex()方法string.rindex()方法返回字符串內子字符串的最高索引rindex()的語法為:str.rindex(sub[,start [,end]])string.rindex()參數
  • 內網滲透:獲取Windows內Hash密碼的方法總結
    在內網滲透中,當攻擊者獲取到內網某臺機器的控制權後,會議被攻陷的主機為跳板,通過收集域內憑證等各種方法,訪問域內其他機器,進一步擴大資產範圍。通過此類手段,攻擊者最終可能獲得域控制器的訪問權限,甚至完全控制基於Windows作業系統的整個內網環境,控制欲環境下的全部機器。
  • 一日一技:Python中的string.isdigit()方法
    pythonstring.isdigit()方法如果字符串中的所有字符都是數字格式,則isdigit()方法將返回True。 如果不是,則返回False。isdigit()的語法是:string.isdigit()isdigit()參數:isdigit()不接受任何參數.
  • 面試官:String長度有限制嗎?是多少?
    是的有限制,但是是在有先提條件下的,我們看看String中返回length的方法。這裡定義的 u2 string_index 表示的是常量池的有效索引,其類型是CONSTANT_Utf8_info 結構體表示的,這裡我們需要注意的是其中定義的length我們看下面這張圖。
  • 利用Hashcat破解WiFi密碼
    本質上,Hashcat 3.0是一款高級密碼恢復工具,可以利用CPU或GPU資源來攻擊160多種哈希類型的密碼準備hashcat(5.1)kali自帶cap數據包字典一份(為了節約時間 就不演示枚舉了)cap文件轉化為hccap格式aircrack-ng <out.cap> -J <out.hccap>需要注意的是:此種方法轉換的數據包只適應比較早的hashcat,新版的已經廢棄。