成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

java中的hashCode

cnTomato / 1166人閱讀

摘要:相關(guān)的文章網(wǎng)上很多了寫這個(gè)主要是按自己的思路進(jìn)行記錄是什么中的實(shí)現(xiàn)是一個(gè)本地方法生成一個(gè)表征當(dāng)前對(duì)象實(shí)例的特征值具體的實(shí)現(xiàn)根據(jù)的實(shí)現(xiàn)可能會(huì)不同中實(shí)際計(jì)算的函數(shù)的實(shí)現(xiàn)如下為時(shí)是直接使用的內(nèi)存地址但默認(rèn)使用的是的隨

hashcode相關(guān)的文章網(wǎng)上很多了, 寫這個(gè)主要是按自己的思路進(jìn)行記錄

hashCode是什么

Object中的hashCode實(shí)現(xiàn)是一個(gè)本地方法, 生成一個(gè)表征當(dāng)前對(duì)象實(shí)例的特征值.

public native int hashCode();

具體的實(shí)現(xiàn)根據(jù)jvm的實(shí)現(xiàn)可能會(huì)不同. JDK1.8中實(shí)際計(jì)算hashcode的get_next_hash函數(shù)的實(shí)現(xiàn)如下(src/share/vm/runtime/synchronizer.cpp)

static inline intptr_t get_next_hash(Thread * Self, oop obj) {
  intptr_t value = 0 ;
  if (hashCode == 0) {
     // This form uses an unguarded global Park-Miller RNG,
     // so it"s possible for two threads to race and generate the same RNG.
     // On MP system we"ll have lots of RW access to a global, so the
     // mechanism induces lots of coherency traffic.
     value = os::random() ;
  } else
  if (hashCode == 1) {
     // This variation has the property of being stable (idempotent)
     // between STW operations.  This can be useful in some of the 1-0
     // synchronization schemes.
     intptr_t addrBits = intptr_t(obj) >> 3 ;
     value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ;
  } else
  if (hashCode == 2) {
     value = 1 ;            // for sensitivity testing
  } else
  if (hashCode == 3) {
     value = ++GVars.hcSequence ;
  } else
  if (hashCode == 4) {
     value = intptr_t(obj) ;
  } else {
     // Marsaglia"s xor-shift scheme with thread-specific state
     // This is probably the best overall implementation -- we"ll
     // likely make this the default in future releases.
     unsigned t = Self->_hashStateX ;
     t ^= (t << 11) ;
     Self->_hashStateX = Self->_hashStateY ;
     Self->_hashStateY = Self->_hashStateZ ;
     Self->_hashStateZ = Self->_hashStateW ;
     unsigned v = Self->_hashStateW ;
     v = (v ^ (v >> 19)) ^ (t ^ (t >> 8)) ;
     Self->_hashStateW = v ;
     value = v ;
  }

  value &= markOopDesc::hash_mask;
  if (value == 0) value = 0xBAD ;
  assert (value != markOopDesc::no_hash, "invariant") ;
  TEVENT (hashCode: GENERATE) ;
  return value;
}

hashcode為4時(shí)是直接使用的內(nèi)存地址, 但默認(rèn)使用的是hashcode>=5的隨機(jī)算法. 可以用JVM parameter -XX:hashCode來調(diào)整.
查了下, xor-shift scheme是弗羅里達(dá)州立大學(xué)一位叫做George Marsaglia的老師發(fā)明的使用位移和異或運(yùn)算生成隨機(jī)數(shù)的方法, 所以在計(jì)算機(jī)上運(yùn)算速度非???移位指令需要的機(jī)器周期更少).有興趣的可以去深入了解.

hashCode和equals方法

hashCode是由散列方法得來的, 所以不同對(duì)象按hashCode方法計(jì)算的散列值, 是可能相同的.
類似于存在兩個(gè)不同串擁有相同的MD5值, 并且可能存在未知的其它串MD5值相同.

所以hashCode相同的對(duì)象, 并不一定是相等的, 需要通過equals方法比較.
如果兩個(gè)對(duì)象的equals為true, 那么這兩個(gè)對(duì)象的HashCode一定相同.

兩個(gè)對(duì)象的hashCode值相同, 對(duì)于其作為hashmap的key沒有影響, 即使映射到同一個(gè)槽中, 也可以通過對(duì)比key本身來進(jìn)行區(qū)分.

equals需要滿足數(shù)個(gè)性質(zhì):
自反性, 對(duì)稱性, 傳遞性, 一致性.

對(duì)稱性: 如果x.equals(y)返回是true,那么y.equals(x)也應(yīng)該返回是true
自反性: x.equals(x)返回是true
傳遞性: 如果x.equals(y)返回是true,而且y.equals(z)返回是true,那么z.equals(x)也應(yīng)該返回是true
一致性: 如果x.equals(y)返回是true,只要x和y內(nèi)容一直不變, 那么x.equals(y)始終都返回都是true

這個(gè)其實(shí)也很好理解, 簡(jiǎn)單點(diǎn)思考可看作是兩個(gè)數(shù)字在比較, 那么滿足這些性質(zhì)便是理所當(dāng)然.

判斷對(duì)象相等需要重寫equals方法, 否則會(huì)調(diào)用Objectequals方法.

為什么重寫equals方法, 通常需要重寫hashCode方法?
假設(shè)現(xiàn)在有一個(gè)類Apple, 有兩個(gè)屬性color和weight. 比較兩個(gè)Apple類的實(shí)例A和B是否相等(當(dāng)然其中一個(gè)可能不是其實(shí)例), 實(shí)際等價(jià)于判斷兩者的兩個(gè)屬性是否都相等; 如果不重寫hashCode方法, 當(dāng)new一個(gè)新的Apple實(shí)例C, 將其color和weight屬性設(shè)置成與B相同, 這就導(dǎo)致B.equals(C)時(shí)兩者的hashCode不一致, 會(huì)產(chǎn)生理解上的混淆.

重寫hashCode的經(jīng)典方式是使用17和31散列碼的實(shí)現(xiàn):

public class Apple {
    private String color;
    private int weight;

    @Override
    public boolean equals(Object o) {
        if (o == this) return true;
        if (!(o instanceof Apple)) {
            return false;
        }
        Apple apple = (Apple) o;
        return apple.color.equals(color) &&
                apple.weight == weight;
    }

    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + color.hashCode();
        result = 31 * result + weight;
        return result;
    }
}

除此之外, 可以使用java.util.Objects去重寫equalshashCode, 也可以使用Apache Commons Lang的LangEqualsBuilderHashCodeBuilder方法. 這兩種方式也是對(duì)于17和31散列碼思想的封裝實(shí)現(xiàn).

集合類的hashCode

AbstractSet中的實(shí)現(xiàn), 對(duì)所有元素的hashCode對(duì)應(yīng)的int值進(jìn)行累加求和. 這樣的話, 兩個(gè)都包括"a", "b", "c"三個(gè)元素的HashSet, 不論添加次序, 其hashCode是一樣的.

public int hashCode() {
        int h = 0;
        Iterator i = iterator();
        while (i.hasNext()) {
            E obj = i.next();
            if (obj != null)
                h += obj.hashCode();
        }
        return h;
    }

AbstractList中的實(shí)現(xiàn), 使用了31讓結(jié)果更分散.

public int hashCode() {
        int hashCode = 1;
        for (E e : this)
            hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
        return hashCode;
    }

AbstractMap是遍歷將每個(gè)entry的hashCode累加. 等等.

如果兩個(gè)集合對(duì)象的hashCode相等, 完全無法說明這兩個(gè)對(duì)象相等, 但如果不等, 說明這兩個(gè)對(duì)象肯定是不等的. 可作為一個(gè)快速判斷不等的方案.

緩存對(duì)象的hashCode

hashCode每次都是實(shí)時(shí)計(jì)算的, 雖然其是一個(gè)本地方法, 速度非??? 如果有大量重復(fù)使用的場(chǎng)景, 可以考慮像Integer內(nèi)部緩存int值為-128到127的對(duì)象一樣進(jìn)行緩存.

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69178.html

相關(guān)文章

  • 【碼藝雜談】Java中的相同與不同

    摘要:如果根據(jù)方法得到兩個(gè)對(duì)象不相同,那么兩個(gè)對(duì)象的方法的結(jié)果不一定不相同,我們可以利用這一點(diǎn)來提高散列表的性能。最后回到文章開頭的問題,如何判斷兩個(gè)對(duì)象或值是否相同這個(gè)問題其實(shí)有兩方面的含義,一方面是判斷的方法,另一方面是判斷的效率。 Java中有很多場(chǎng)景需要判斷兩個(gè)對(duì)象或者兩個(gè)值,那么 判斷是否相同的依據(jù)是什么? 如何判斷是否相同呢? 為了解釋這個(gè)問題,我們從Java語言的根說起,那...

    xingqiba 評(píng)論0 收藏0
  • 【金三銀四】面試題之java基礎(chǔ)

    摘要:中,任何未處理的受檢查異常強(qiáng)制在子句中聲明。運(yùn)行時(shí)多態(tài)是面向?qū)ο笞罹璧臇|西,要實(shí)現(xiàn)運(yùn)行時(shí)多態(tài)需要方法重寫子類繼承父類并重寫父類中已 1、簡(jiǎn)述Java程序編譯和運(yùn)行的過程:答:① Java編譯程序?qū)ava源程序翻譯為JVM可執(zhí)行代碼--字節(jié)碼,創(chuàng)建完源文件之后,程序會(huì)先被編譯成 .class 文件。② 在編譯好的java程序得到.class文件后,使用命令java 運(yùn)行這個(gè) .c...

    Yangyang 評(píng)論0 收藏0
  • 【金三銀四】面試題之java基礎(chǔ)

    摘要:中,任何未處理的受檢查異常強(qiáng)制在子句中聲明。運(yùn)行時(shí)多態(tài)是面向?qū)ο笞罹璧臇|西,要實(shí)現(xiàn)運(yùn)行時(shí)多態(tài)需要方法重寫子類繼承父類并重寫父類中已 1、簡(jiǎn)述Java程序編譯和運(yùn)行的過程:答:① Java編譯程序?qū)ava源程序翻譯為JVM可執(zhí)行代碼--字節(jié)碼,創(chuàng)建完源文件之后,程序會(huì)先被編譯成 .class 文件。② 在編譯好的java程序得到.class文件后,使用命令java 運(yùn)行這個(gè) .c...

    Barrior 評(píng)論0 收藏0
  • Java中的 equals() 和 hashCode() 契約

    摘要:我們使用調(diào)試器卻發(fā)現(xiàn)在中已經(jīng)存儲(chǔ)了這個(gè)對(duì)象。中和有一個(gè)契約如果兩個(gè)對(duì)象相等的話,它們的必須相等但如果兩個(gè)對(duì)象的相等的話,這兩個(gè)對(duì)象不一定相等。的結(jié)構(gòu)能夠快速找到一個(gè)對(duì)象,而不是進(jìn)行較慢的線性查找??梢钥醋魇菙?shù)組的數(shù)組。 java.lang.Object類中有兩個(gè)非常重要的方法: public boolean equals(Object obj) public int hashCode...

    rainyang 評(píng)論0 收藏0
  • 理解Java中HashMap的工作原理

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

    xiangchaobin 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<