hashcode和equals
首先,我們打開Object類,找到public native int hashCode();
方法,看下它的註釋是什麼,翻譯後大概是這樣的:
- 在 Java 應用程序執行期間,在對同一對象多次調用 hashCode 方法時,必須一致地返回相同的整數,前提是將對象進行 equals 比較時所用的信息沒有被修改。從某一應用程序的一次執行到同一應用程序的另一次執行,該整數無需保持一致。
- 如果根據 equals(Object) 方法,兩個對象是相等的,那麼對這兩個對象中的每個對象調用 hashCode 方法都必須生成相同的整數結果。
- 如果根據 equals(java.lang.Object) 方法,兩個對象不相等,那麼對這兩個對象中的任一對象上調用 hashCode 方法不要求一定生成不同的整數結果。但是,程序員應該意識到,爲不相等的對象生成不同整數結果可以提高哈希表的性能。
- 在合理可行的範圍內,Object類定義的hashCode方法的確爲不同對象返回不同的整數。 (這通常通過將對象的內部地址轉換爲整數來實現,但是Java™編程語言不強制要求此實現技術。)
所以,結論就很明顯了:
- hashCode相等的類,equals不一定相等;
- equals相等的類,hashCode必然相等;
- hashCode一般是內存地址,但也不一定。
如果大家正在尋找一個java的學習環境,或者在開發中遇到困難,可以加入我們的java學習圈,點擊即可加入,共同學習,節約學習時間,減少很多在學習中遇到的難題。
hashcode的生成規則。
jdk8的openjdk源碼地址:http://hg.openjdk.java.net/jdk8,其他版本也可以在這個網站查到。
openjdk:
- corba:不流行的多語言、分佈式通訊接口
- hotspot:Java 虛擬機
- jaxp:XML 處理
- jaxws:一組 XML web services 的 Java API
- jdk:java 開發工具包
- langtools:Java 語言工具
- nashorn:JVM 上的 JavaScript 運行時。
在hotspot下的src/share/vm/runtime/synchronizer.cpp文件中,能看到hashcode生成源碼:
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 = cast_from_oop<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 = cast_from_oop<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 == 0,此類方案返回一個Park-Miller僞隨機數生成器生成的隨機數;OpenJdk 6 &7的默認實現;
- hashCode == 1,此類方案將對象的內存地址,做移位運算後與一個隨機數進行異或得到結果;
- hashCode == 2,此類方案返回固定的1;
- hashCode == 3,此類方案返回一個自增序列的當前值;
- hashCode == 4,此類方案返回當前對象的內存地址;
- hashcode >= 5,Marsaglia XORshift隨機數算法,使用位移和異或運算生成隨機數的方法;