讀《阿里巴巴Java開發(fā)手冊》的一點思考

1.前言

最近在上下班的地鐵上把《阿里巴巴Java開發(fā)手冊》讀了一遍钾怔,感覺獲益匪淺。讀的過程中也有一些思考和疑惑奸忽,就抽時間親自嘗試了一下阎肝。下面用這篇文章把我的問題和答案整理出來甩骏。

2.正文

  1. 手冊里提到,如果重寫equals()方法先慷,就必須重寫hashCode()方法饮笛,網(wǎng)上查了一下如何重寫hashCode(),發(fā)現(xiàn)好多重寫方法里都出現(xiàn)了31這個神奇的數(shù)字论熙。以下是String類的hashCode()實現(xiàn):
@Override public int hashCode() {
        int hash = hashCode;
        if (hash == 0) {
            if (count == 0) {
                return 0;
            }
            for (int i = 0; i < count; ++i) {
                hash = 31 * hash + charAt(i);
            }
            hashCode = hash;
        }
        return hash;
    }

這個magic number勾起了我的興趣福青,重寫hashCode()方法為什么會不約而同地用到31這個數(shù)字呢?
在網(wǎng)上查了一下脓诡,這個問題也沒有標準的答案无午,以下是我查找到的一些比較令人信服的答案:

  • 每個對象根據(jù)值計算HashCode,這個code大小雖然不奢求必須唯一(因為這樣通常計算會非常慢)祝谚,但是要盡可能的不要重復,因此基數(shù)要盡量的大且計算出來的值不要溢出宪迟,計算出來的hash地址越大,所謂的“沖突”就越少交惯,查找起來效率也會提高次泽。
  • 素數(shù)的特性能夠使得它和其他數(shù)相乘后得到的結果比其他方式更容易產(chǎn)成唯一性,也就是hashcode值的沖突概率最小席爽。
  • 31*N可以被編譯器優(yōu)化為左移5位后減N意荤,有較高的性能。

比較權威的答案是Stack OverFlow上:
According to Joshua Bloch's『Effective Java』:
The value 31 was chosen because it is an odd prime. If it were even and the multiplication overflowed, information would be lost, as multiplication by 2 is equivalent to shifting.
The advantage of using a prime is less clear, but it is traditional.
A nice property of 31 is that the multiplication can be replaced by a shift and a subtraction for better performance: 31 * i == (i << 5) - i.
Modern VMs do this sort of optimization automatically.

翻譯:
根據(jù) Joshua Bloch 的著作『Effective Java』:
設計者選擇 31 這個值是因為它是一個奇質數(shù)拳昌。如果它是一個偶數(shù)袭异,在使用乘法當中產(chǎn)生數(shù)值溢出時,原有數(shù)字的信息將會丟失炬藤,因為乘以二相當于位移御铃。
選擇質數(shù)的優(yōu)勢不是那么清晰,但是這是一個傳統(tǒng)沈矿。
31 的一個優(yōu)良的性質是:乘法可以被位移和減法替代: 31 * i == (i << 5) - i
現(xiàn)代的 VM 可以自行完成這個優(yōu)化上真。

  1. 手冊里還留下了一個問題:
List<String> a = new ArrayList<String>();
        a.add("1");
        a.add("2");
        for (String temp : a) {
            if ("1".equals(temp)) {
                a.remove(temp);
            }
        }

這段代碼執(zhí)行時不會拋出異常,但是如果將equals前面的"1"換成"2"就會拋出ConcurrentModificationException羹膳,使用Iterator來進行刪除操作也不會拋出異常睡互,這是為什么呢?

通過分析源碼發(fā)現(xiàn)陵像,在Iterator的remove()和next()方法中都調用了checkForComodification()方法:

final void checkForComodification() {
        if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
    }

就是在這里拋出了ConcurrentModificationException.

modCount:修改次數(shù)
expectedModCount:預期的修改次數(shù)

使用ArrayList的remove()就珠,只會使modCount++,不會修改expectedModCount
使用Iterator的remove()醒颖,則是expectedModCount = ++modCount

前面提到remove("1")時不會拋出異常妻怎,這是因為foreach方法其實也是調用了Iterator的hasNext()和next(),next()里調了checkForComodification()泞歉,hasNext()卻沒調用逼侦,remove("1")后匿辩,hasNext()返回false,就不會走到next()榛丢,所以也就不會拋出異常了铲球,這其實只是一個巧合。
所以:不要在foreach循環(huán)里進行元素的remove/add操作晰赞,remove元素請使用Iterator方式稼病,如果并發(fā)操作,需要對Iterator對象加鎖掖鱼。
具體的分析過程可以參考:http://blog.csdn.net/qq_28816195/article/details/78433544

3.結語

參加工作后才發(fā)現(xiàn)溯饵,代碼規(guī)范其實是極其重要的,優(yōu)雅的代碼便于理解和維護锨用,更加節(jié)省時間丰刊。就像通過一個人的字就能大概看出這是一個什么樣的人,代碼亦是如此增拥。剛畢業(yè)不久的我啄巧,更應該培養(yǎng)好的代碼規(guī)范,這對今后的成長必然是大有益處的掌栅。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末秩仆,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子猾封,更是在濱河造成了極大的恐慌澄耍,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晌缘,死亡現(xiàn)場離奇詭異齐莲,居然都是意外死亡,警方通過查閱死者的電腦和手機磷箕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門选酗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人岳枷,你說我怎么就攤上這事芒填。” “怎么了空繁?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵殿衰,是天一觀的道長。 經(jīng)常有香客問我盛泡,道長闷祥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任饭于,我火速辦了婚禮蜀踏,結果婚禮上,老公的妹妹穿的比我還像新娘掰吕。我一直安慰自己果覆,他們只是感情好,可當我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布殖熟。 她就那樣靜靜地躺著局待,像睡著了一般。 火紅的嫁衣襯著肌膚如雪菱属。 梳的紋絲不亂的頭發(fā)上钳榨,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天,我揣著相機與錄音纽门,去河邊找鬼薛耻。 笑死,一個胖子當著我的面吹牛赏陵,可吹牛的內容都是我干的饼齿。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蝙搔,長吁一口氣:“原來是場噩夢啊……” “哼缕溉!你這毒婦竟也來了?” 一聲冷哼從身側響起吃型,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤证鸥,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后勤晚,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體枉层,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年赐写,在試婚紗的時候發(fā)現(xiàn)自己被綠了返干。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡血淌,死狀恐怖矩欠,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情悠夯,我是刑警寧澤癌淮,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站沦补,受9級特大地震影響乳蓄,放射性物質發(fā)生泄漏。R本人自食惡果不足惜夕膀,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一虚倒、第九天 我趴在偏房一處隱蔽的房頂上張望美侦。 院中可真熱鬧,春花似錦魂奥、人聲如沸菠剩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽具壮。三九已至,卻和暖如春哈蝇,著一層夾襖步出監(jiān)牢的瞬間棺妓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工炮赦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留怜跑,地道東北人。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓吠勘,卻偏偏與公主長得像妆艘,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子看幼,可洞房花燭夜當晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內容