hashCode

hashCode作用

当在集合中判断是否存在(包含)某元素时,可以使用equals方法实现。但如果元素过多,使用equals方法判断则会带来性能问题。
一种有效的方式是比较哈希码(hashCode),这样就可以将一个元素用一个整数来代替。以HashMap为例,其实现流程如下:
(1) 添加一个元素时,使用其哈希码计算内部数组的索引(即所谓的桶)
(2) 如果不相等元素有相同的哈希码,那么他们在同一个桶上并且捆绑在一起,如通过列表处理哈希冲突。
(3) 当进行contains操作时,使用带查找元素的哈希码计算出桶值(索引值),如果对应索引值不存在元素,则直接返回,否则对实例进行equals比较。
使用这种方式,可以大大减少equals的执行次数。
相等的元素一定具有有相同的哈希值。其逆反命题是:哈希码不同,则对应的元素一定不同。
所以,在重写equals方法时,一定要重写hashCode方法

hashCode 使用准则

hashCode通用约定:
(1) 调用运行Java应用程序中的同一对象,hashCode方法必须始终返回相同的整数。这个整数不需要在不同的Java应用程序中保持一致。
(2) 根据equals(Object)的方法,如果两个对象是相等的,两个对象调用hashCode方法必须产生相同的结果。
(3) 根据equals(Object)的方法,如果两个对象是不相等的,那么两个对象调用hashCode方法并不一定产生不同的整数的结果。
Object的hashCode方法是一个native方法,注释中描述hashCode返回的是由对象存储地址转化得到的值

public native int hashCode();

这里记录Java源码(Java 8)实现:

static inline intptr_t get_next_hash(Thread * Self, oop obj) {
  intptr_t value = 0 ;
  if (hashCode == 0) {
    // 根据Park-Miller伪随机数生成器生成的随机数
     value = os::random() ;
  } else if (hashCode == 1) {
     // 此类方案将对象的内存地址,做移位运算后与一个随机数进行异或得到结果
     intptr_t addrBits = cast_from_oop<intptr_t>(obj) >> 3 ;
     value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ;
  } else if (hashCode == 2) {
     value = 1 ;            // 返回固定的1
  } else if (hashCode == 3) {
     value = ++GVars.hcSequence ;  // 返回一个自增序列的当前值
  } else if (hashCode == 4) {
     value = cast_from_oop<intptr_t>(obj) ;  // 对象地址
  } else {
     // 通过和当前线程有关的一个随机数+三个确定值
     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;
}

String中重写hashCode实现如下:

/* The hash code for a
 * {@code String} object is computed as
 * <blockquote><pre>
 * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
 */
public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        hash = h = isLatin1() ? StringLatin1.hashCode(value)
                                : StringUTF16.hashCode(value);
    }
    return h;
}

参考

https://github.com/JetBrains/jdk8u_hotspot/blob/master/src/share/vm/runtime/synchronizer.cpp#L560 hashCode实现
https://blog.csdn.net/changrj6/article/details/100043822 Java Object.hashCode()源码分析
https://www.sitepoint.com/how-to-implement-javas-hashcode-correctly/ hashCode
http://www.codeceo.com/article/java-hashcode-implement.html 如何正确实现Java中的hashCode方法

原创不易,如果本文对您有帮助,欢迎关注我,谢谢 ~_~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值