• equals(): 反映的是对象或变量具体的值,即两个对象里面包含的值—可能是对象的引用,也可能是值类型的值。
  • hashCode(): 计算出对象实例的哈希码,并返回哈希码,又称为散列函数。根类Object的hashCode()方法的计算依赖于对象实例的D(内存地址),故每个Object对象的hashCode都是唯一的;当然,当对象所对应的类重写了hashCode()方法时,结果就截然不同了。
    在批量的对象比较中,hashCode 要比 equals 来得快,很多集合都用到了 hashCode,比如 HashTable。

Java 中几个常用的哈希码(hashCode)的算法:

  1. Object 类的 hashCode:返回对象的经过处理后的内存地址,由于每个对象的内存地址都不一样,所以哈希码也不一样。这个是 native 方法,取决于 JVM 的内部设计,一般是某种 C 地址的偏移。
  2. String 类的 hashCode:根据 String 类包含的字符串的内容,根据一种特殊算法返回哈希码,只要字符串的内容相同,返回的哈希码也相同。
    image.png
  3. Integer 等包装类,返回的哈希码就是 Integer 对象里所包含的那个整数的数值,例如 Integer i1 = new Integer(100), i1.hashCode 的值就是 100 。由此可见,2个一样大小的Integer对象,返回的哈希码也一样。
  4. int,char 这样的基础类,它们不需要 hashCode,如果需要存储时,将进行自动装箱操作,计算方法同上。

    二者比较

    两个obj,如果 equals() 相等 => hashCode() 一定相等
    两个obj,如果 hashCode() 相等,equals() 不一定相等(Hash散列值有冲突的情况,虽然概率很低)。
    所以,可以考虑在集合中,判断两个对象是否相等的规则是:
  • 如果hashCode()相等,则查看第二步,否则不相等;
  • 查看equals()是否相等,如果相等,则两obj相等,否则还是不相等。

1、首先 equals() 和 hashcode() 这两个方法都是从object类中继承过来的。

  • equals() 是对两个对象的地址值进行的比较(即比较引用是否相同)。
  • hashCode() 是一个本地方法,它的实现是根据本地机器相关的。

2、Java语言对equals()的要求如下,这些要求是必须遵循的:

  • 对称性:如果 x.equals(y) 返回是 true,那么 y.equals(x) 也应该返回是 true
  • 反射性:x.equals(x) 必须返回是 true
  • 类推性:如果 x.equals(y) 返回是 true,而且 y.equals(z) 返回是 true,那么 z.equals(x) 也应该返回是 true
  • 一致性:如果 x.equals(y) 返回是 true,只要 x 和 y 内容一直不变,重复 x.equals(y) n 次,返回都是 true

任何情况下,x.equals(null),永远返回是 false;x.equals(和 x 不同类型的对象)永远返回是 false。

3、equals() 相等的两个对象,hashcode() 一定相等;反之,hashcode() 不等,一定能推出 equals() 也不等。

hashcode() 相等,equals() 可能相等,也可能不等。为什么选择hashcode方法?

以 java.lang.Object 来理解,JVM 每 new 一个 Object,它都会将这个 Object 丢到一个 Hash 哈希表中去,下次做 Object 的比较或者取这个对象的时候,它会根据对象的 hashcode 再从 Hash 表中取这个对象。提高取对象的效率。具体过程是这样:

  1. new Object(),JVM 根据这个对象的 Hashcode 值,放入到对应的 Hash 表对应的 Key 上,如果不同的对象确产生了相同的 hash 值,也就是发生了 Hash key 相同导致冲突的情况,那么就在这个 Hash key 的地方产生一个链表,将所有产生相同 hashcode 的对象放到这个单链表上去,串在一起。
  2. 比较两个对象的时候,首先根据他们的 hashcode 去 hash 表中找他的对象,当两个对象的 hashcode 相同(这两个对象放在 Hash 表中的同一个key上),那么他们一定在这个 key 的链表上。那么此时就只能根据 Object 的 equal 方法来比较这个对象是否 equal。当两个对象的 hashcode 不同的话,肯定他们不能 equal。

可能经过上面理论的讲一下大家都迷糊了,我也看了之后也是似懂非懂的。下面我举个例子详细说明下。
  list是可以重复的,set是不可以重复的。那么set存储数据的时候是怎样判断存进的数据是否已经存在。使用equals()方法呢,还是hashcode()方法。
  假如用equals(),那么存储一个元素就要跟已存在的所有元素比较一遍,比如已存入100个元素,那么存101个元素的时候,就要调用equals方法100次。
  但如果用hashcode()方法的话,他就利用了hash算法来存储数据的。
  这样的话每存一个数据就调用一次hashcode()方法,得到一个hashcode值及存入的位置。如果该位置不存在数据那么就直接存入,否则调用一次equals()方法,不相同则存,相同不存。这样下来整个存储下来不需要调用几次equals方法,虽然多了几次hashcode方法,但相对于前面来讲效率高了不少。