重載和重寫


equals和==的區別

  • ==主要用來比較基本數據類型,而equal主要用來比較對象是否相等。equal是Object的方法。
  • 如果兩者都用來比較對象的相等性,那么如果兩個引用地址相同,那么==就返回true,但是如果對象重寫了equal方法,那么就需要根據實際情況進行分析。比如String對象,根據字符串內容是否相等來返回true還是false。比如Integer,根據數值是否相等來返回true還是false。

hashCode

hashCode()是Obejct類的中一個方法,返回值是int。
hashCOde()就是根據一定的規則將對象的信息(對象的字段、對象的地址)散列成一個散列值。

hahCode的作用

hashCode是為了查找的快捷性。主要用於HashSet、HashMap、HashTable等散列集合。
hashCode()返回值不一定是對象的內存地址,只能說有些時候確實返回的值是內存地址但是大部分時候不是。(針對Object類)
如何在散列集合存放不同的對象,判斷集合中是否存在這個對象。

  1. 用equals來一一比對,但是這樣子如果集合越大所花費的資源也越大。
  2. 這個時候使用對象的hashCode方法的話,集合中會存在一個hash表。
  3. 先判斷是否對象的hashCOde的值已經存在與這個hash表中,如果不存在就直接放入集合中,
  4. 如果存在,再使用equal比對hashCOde值相同的對象,如果equal比對true則不能放入集合,如果比對false則放入集合。這樣就大大減少了執行equal方法的次數。

hashCode()與equals()的關系

先通過hashcode來比較,如果hashcode相等,那么就用equals方法來比較兩個對象是否相等,用個例子說明:上面說的hash表中的8個位置,就好比8個桶,每個桶里能裝很多的對象,對象A通過hash函數算法得到將它放到1號桶中,當然肯定有別的對象也會放到1號桶中,如果對象B也通過算法分到了1號桶,那么它如何識別桶中其他對象是否和它一樣呢,這時候就需要equals方法來進行篩選了。

  1. 如果兩個對象的equals相等,那么其hashCode值必相等。
  2. 如果兩個對象的hashCOde值相等,其equals不一定相等。

equals()方法重寫時hashCode()也必須要重寫

讓equals和hashCode在邏輯上始終保持一致性。不然一個對象重寫了equals方法卻沒有重寫hashCode方法后,兩個沒有關系的對象equals相等,但是hashCode不相等。

hashCode重寫的規范

hash算法盡量不要依賴於對象中易變的數據,否則你存進去時散列值和你取出來的散列值可能不一樣導致取不出來數據。

如果Object沒有重寫hashCode方法那么hashCode()是如何算出來?

通過下面代碼可以看出hashCode值有時是靠對象內存地址算出來的,但具體還是取決與JVM的具體實現。

// hashCode() generation :
//
// Possibilities:
// * MD5Digest of {obj,stwRandom}
// * CRC32 of {obj,stwRandom} or any linear-feedback shift register function.
// * A DES- or AES-style SBox[] mechanism
// * One of the Phi-based schemes, such as:
//   2654435761 = 2^32 * Phi (golden ratio)
//   HashCodeValue = ((uintptr_t(obj) >> 3) * 2654435761) ^ GVars.stwRandom ;
// * A variation of Marsaglia's shift-xor RNG scheme.
// * (obj ^ stwRandom) is appealing, but can result
//   in undesirable regularity in the hashCode values of adjacent objects
//   (objects allocated back-to-back, in particular).  This could potentially
//   result in hashtable collisions and reduced hashtable efficiency.
//   There are simple ways to "diffuse" the middle address bits over the
//   generated hashCode values:
//

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.
     // 地址基礎上hack
     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;
}

引用鏈接1
引用鏈接2
如有侵權,告之立刪。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM