一文讲解Java中的equals和hashCode方法

什么是hashCode方法?

  • hashCode()方法的作用是获取哈希码,它会返回一个int整数,定义在Object类中,是一个本地方法;
public native int hashCode();

为什么要有hashCode方法呢?

  • hashCode方法主要用来获取对象的哈希码,哈希码是由对象的内存地址或者对象的属性计算出来,它是一个int类型的整数,通常是不会重复的,因此可以用来作为键值对的键,来提高查询效率;
  • 比如HashMap中的key就是通过hashCode来实现的,通过调用hashCode方法获取键的哈希吗,并将其与右移16位的哈希码进行异或运算;
static final int hash(Object key){
    int h;
    return (key==null)? 0:(h==key.hashCode())^(h>>>16);
}

那么,再提问个问题,为什么重写equals时必须重写hashCode方法呢?

  • 因为基于哈希的集合类,比如HashMap 需要基于这一点来正确存储和查找对象;
  • 具体的说,HashMap通过对象的哈希码将其存储在不同的“桶”中,当查找对象时,它需要使用key的哈希码来确定对象在哪个桶中,然后再通过equals()方法找到对应的对象;
  • 如果重写了equals方法而没有重写hashCode()方法,那么被认为相等的对象可能会有不同的哈希码,从而导致无法在HashMap中正确处理这些对象;

对了,那么为什么两个对象有相同的hashCode值,他们也不一定相等呢?

  • 这主要是由于哈希码的本质和目的所决定的;
  • 哈希码是通过哈希函数将对象映射成一个整数值,其主要目的是在哈希表中快速定位对象的存储位置;
  • 由于哈希函数将一个较大的输入域映射到一个较小的输出域,不同的输入值,即不同的对象,可能会产生相同的输出值,也就是相同的哈希码;
  • 这种情况被称为哈希冲突,当两个不相等的对象发生哈希冲突时,他们会有相同的hashCode;
  • 为了解决哈希冲突的问题,哈希表在处理键时,不仅会比较键对象的哈希码,还会使用equals方法来检查键对象是否真正相等。如果两个对象的哈希码相同,但通过equals方法比较结果为false,那么这两个对象就不被称为相等;
if (p.hash == hash &&
    ((k = p.key) == key || (key != null && key.equals(k))))
    e = p;

我们再来谈下hashCode和equals方法的关系

  • 如果两个对象通过equals相等,它们的hashCode必须相等。否则会导致哈希表类数据结构,比如HashMap、HashSet的行为异常;
  • 在哈希表中,如果equals相等但hashCode不相等,哈希表可能无法正确处理这些对象,导致重复元素或键值冲突的问题;

最后,题外话,问下Java是值传递还是引用传递呢?

  • Java是值传递,不是引用传递;
  • 当一个对象被作为参数传递到方法中时,参数的值就是该对象的引用。引用的值是对象在堆中的地址;
  • 对象是存储在堆中的,所以传递对象的时候,可以理解为把变量存储的对象地址给传递过去

一文讲解Java中的equals和hashCode方法_第1张图片
引用类型的变量有什么特点呢?

  • 引用类型的变量存储的是对象的地址,而不是对象本身。因此,引用类型的变量在传递时,传递的是对象的地址,也就是说,传递的是引用的值;

你可能感兴趣的:(JavaSE,java,哈希算法,散列表)