Java 魔法Part 1:java.net.URL

原文 http://mishadoff.com/blog/java-magic-part-1-java-dot-net-dot-url/

這篇文章比較老了拍皮,也有很多人翻譯格了,但是好像都是google翻譯的,沒有體現(xiàn)出作者的風(fēng)趣。感覺作者還是很皮的晴埂,他的這系列文章都很有意思痕囱。


最近, 我在reddit上發(fā)現(xiàn)了一個(gè)非常有趣的Java代碼片段(有一點(diǎn)修改)

HashSet set = new HashSet();
set.add(new URL("http://google.com"));
set.contains(new URL("http://google.com"));
Thread.sleep(60000);
set.contains(new URL("http://google.com"));

你認(rèn)為第三代碼和第五行代碼的結(jié)果會是什么?
既然問了這個(gè)問題舟奠,那很明顯不是true, true竭缝。先思考兩分鐘。

好了沼瘫,在大多數(shù)時(shí)候結(jié)果是true, false 這是因?yàn)槟氵B接了互聯(lián)網(wǎng)(否則你怎么能看到這篇文章呢抬纸?)關(guān)閉你的網(wǎng)絡(luò)連接或者WiFi你將會得到true, true
問題的原因在于該類方法hashCode() 和 equals()的實(shí)現(xiàn)邏輯耿戚。
讓我們看下它是如何計(jì)算hashCode的:

public synchronized int hashCode() {
  if (hashCode != -1)
    return hashCode;
  hashCode = handler.hashCode(this);
  return hashCode;
}

我們可以看到hashCode是一個(gè)實(shí)例變量并且只計(jì)算一次湿故。這是有意義的,因?yàn)閁RL是不可變的膜蛔。handler是什么坛猪?它是URLStreamHandler子類的實(shí)例,具體依賴于不同的協(xié)議類型(file,http,ftp)皂股∈裕看下java.net.URL的Java文檔說明:

The hash code is based upon all the URL components relevant for URL comparison. As such, this operation is a blocking operation.

等一下! 阻塞式操作?呜呐!

對不起我昨天沒有收新郵件就斤,因?yàn)閔ashCode計(jì)算阻塞了

或者更好的例子:

不是的,媽媽蘑辑,我不能看X片战转。你知道的,在做hashCode計(jì)算呢(這個(gè)實(shí)在是太皮了)

好的就當(dāng)他是阻塞操作吧以躯。另一個(gè)奇葩的地方槐秧,當(dāng)計(jì)算hashCode的時(shí)候這個(gè)handler竟然會解析ip地址啄踊。更準(zhǔn)確的說法是會嘗試去解析ip地址,如果無法解析ip地址的話刁标,會根據(jù)host地址去計(jì)算hashCode颠通。我們拿google.com舉個(gè)例子。當(dāng)host的ip是動態(tài)的時(shí)候膀懈,或者說有一個(gè)域名解析的負(fù)載均衡的時(shí)候顿锰,不好的事情就發(fā)生了。在這種情況下同一個(gè)域名會得到不同的hashCode值启搂,如果用在HashSet就會有兩個(gè)(或者多個(gè))實(shí)例在集合列表里硼控。這一點(diǎn)也不好。順便說一下胳赌,hashCode 和 equals 的性能也是很不好的牢撼,因?yàn)閁RLStreamHandler會開啟一個(gè)URLConnection,不過這是另外一個(gè)話題了疑苫。


附Java里URLStreamHandler代碼實(shí)現(xiàn)

protected int hashCode(URL u) {
        int h = 0;

        // Generate the protocol part.
        String protocol = u.getProtocol();
        if (protocol != null)
            h += protocol.hashCode();

        // Generate the host part.
        InetAddress addr = getHostAddress(u);
        if (addr != null) {
            h += addr.hashCode();
        } else {
            String host = u.getHost();
            if (host != null)
                h += host.toLowerCase().hashCode();
        }

        // Generate the file part.
        String file = u.getFile();
        if (file != null)
            h += file.hashCode();

        // Generate the port part.
        if (u.getPort() == -1)
            h += getDefaultPort();
        else
            h += u.getPort();

        // Generate the ref part.
        String ref = u.getRef();
        if (ref != null)
            h += ref.hashCode();

        return h;
    }

好消息是Android源碼里對此作了更改

protected int hashCode(URL u) {
        // Android-changed: Avoid network I/O
        // Hash on the same set of fields that we compare in equals().
        return Objects.hash(
                u.getRef(),
                u.getQuery(),
                u.getProtocol(),
                u.getFile(),
                u.getHost(),
                u.getPort());
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末熏版,一起剝皮案震驚了整個(gè)濱河市蜈块,隨后出現(xiàn)的幾起案子院刁,更是在濱河造成了極大的恐慌客蹋,老刑警劉巖坷襟,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渺贤,死亡現(xiàn)場離奇詭異六水,居然都是意外死亡桨啃,警方通過查閱死者的電腦和手機(jī)踩蔚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門不瓶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來胜榔,“玉大人,你說我怎么就攤上這事湃番∝仓” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵吠撮,是天一觀的道長尊惰。 經(jīng)常有香客問我,道長泥兰,這世上最難降的妖魔是什么弄屡? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮鞋诗,結(jié)果婚禮上膀捷,老公的妹妹穿的比我還像新娘。我一直安慰自己削彬,他們只是感情好全庸,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布秀仲。 她就那樣靜靜地躺著,像睡著了一般壶笼。 火紅的嫁衣襯著肌膚如雪神僵。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天覆劈,我揣著相機(jī)與錄音保礼,去河邊找鬼。 笑死责语,一個(gè)胖子當(dāng)著我的面吹牛炮障,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播坤候,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼胁赢,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了铐拐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤练对,失蹤者是張志新(化名)和其女友劉穎遍蟋,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體螟凭,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡虚青,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了螺男。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片棒厘。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖下隧,靈堂內(nèi)的尸體忽然破棺而出奢人,到底是詐尸還是另有隱情,我是刑警寧澤淆院,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布何乎,位于F島的核電站,受9級特大地震影響土辩,放射性物質(zhì)發(fā)生泄漏支救。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一拷淘、第九天 我趴在偏房一處隱蔽的房頂上張望各墨。 院中可真熱鬧,春花似錦启涯、人聲如沸贬堵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽扁瓢。三九已至详恼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間引几,已是汗流浹背昧互。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留伟桅,地道東北人敞掘。 一個(gè)月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像楣铁,于是被迫代替她去往敵國和親玖雁。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 從三月份找實(shí)習(xí)到現(xiàn)在盖腕,面了一些公司赫冬,掛了不少,但最終還是拿到小米溃列、百度劲厌、阿里、京東听隐、新浪补鼻、CVTE、樂視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,246評論 11 349
  • Java繼承關(guān)系初始化順序 父類的靜態(tài)變量-->父類的靜態(tài)代碼塊-->子類的靜態(tài)變量-->子類的靜態(tài)代碼快-->父...
    第六象限閱讀 2,157評論 0 9
  • BAT 常問的 Java基礎(chǔ)39道常見面試題 1.八種基本數(shù)據(jù)類型的大小雅任,以及他們的封裝類 2.引用數(shù)據(jù)類型 3....
    AI喬治閱讀 2,459評論 0 75
  • (一)Java部分 1风范、列舉出JAVA中6個(gè)比較常用的包【天威誠信面試題】 【參考答案】 java.lang;ja...
    獨(dú)云閱讀 7,104評論 0 62
  • 久違的晴天,家長會沪么。 家長大會開好到教室時(shí)硼婿,離放學(xué)已經(jīng)沒多少時(shí)間了。班主任說已經(jīng)安排了三個(gè)家長分享經(jīng)驗(yàn)禽车。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,523評論 16 22