java.lang.Object
类中定义了 equals()
和 hashCode()
方法,Object
类是所有 Java 类的基类,所以所有的 Java 类都实现了这两个方法。
equals()
equals()
方法的作用是用来判断两个对象是否相等
。
equals()
方法定义在 java.lang.Object
类中。通过判断两个对象的地址是否相等(即,是否是同一个对象)来区分它们是否相等。源码如下:
public boolean equals() {
return (this == obj);
}
既然 Object
类中定义了 equals()
方法,这就意味着所有的 Java 类都实现了 equals() 方法,所有的类都可以通过 equals()
方法去比较两个对象是否相等。但是,使用默认的 equals()
方法,等价于 ==
。因此,通常需要重写 equals()
方法:若两个对象的内容相等,则 equals()
方法返回 true
;否则,返回 fasle
。
equals()
方法的使用分为以下两种情况:
- 若某个类没有重写
equals()
方法,当它通过equals()
方法比较两个对象时,实际上是比较两个对象是不是同一个对象。这时,等价于通过==
去比较这两个对象。 - 可以重写类的
equals()
方法,来让equals()
方法通过其它方式比较两个对象是否相等。通常的做法是:若两个对象的内容相等,则equals()
方法返回true
;否则,返回fasle
。
==
的作用是判断两个对象的地址是否相等(即,判断两个对象是不是同一个对象);equals()
的作用是判断两个对象是否相等。
hashCode()
hashCode()
方法的作用是获取哈希码
,也称为散列码;它实际上是返回一个 int 值。这个哈希码的作用是确定该对象在哈希表中的索引位置。
hashCode()
方法定义在 java.lang.Object
类中,这就意味着所有的 Java 类都实现了 hashCode()
方法。
虽然,每个 Java 类都实现了 hashCode()
方法,但是,类的 hashCode()
方法一般仅用在散列表中(用于确定该类的每一个对象在散列表中的位置)。
散列表:Java 集合中本质是散列表的类,如 HashMap、Hashtable、HashSet 等。也就是说:hashCode() 方法在散列表中才有用,在其它情况下没用。在散列表中 hashCode() 方法的作用是获取对象的散列码,进而确定该对象在散列表中的位置。
equals() 和 hashCode() 的关系
Java 对于 eqauls()
方法和 hashCode()
方法是这样规定的:
- 同一对象上多次调用 hashCode() 方法,总是返回相同的整型值。
- 如果 a.equals(b),则一定有 a.hashCode() 一定等于 b.hashCode()。
- 如果 !a.equals(b),则 a.hashCode() 不一定等于 b.hashCode()。此时如果 a.hashCode() 总是不等于 b.hashCode(),会提高 hashtables 的性能。
- a.hashCode()==b.hashCode() 则 a.equals(b) 可真可假
- a.hashCode()!= b.hashCode() 则 a.equals(b) 为假。
上面结论简记:
- 如果两个对象 equals,Java 运行时环境会认为他们的 hashCode 一定相等。
- 如果两个对象不 equals,他们的 hashCode 有可能相等。
- 如果两个对象 hashCode 相等,他们不一定 equals。
- 如果两个对象 hashCode 不相等,他们一定不 equals。
关于 equals() 和 hashCode() 的重要规范
- 规范1:若重写
equals()
方法,有必要重写hashcode()
方法,确保通过equals()
方法判断结果为true
的两个对象具备相等的hashcode()
方法返回值。说得简单点就是:“如果两个对象相同,那么他们的 hashCode 应该相等”。不过请注意:这个只是规范,如果非要写一个类让equals()
方法返回true
而hashCode()
方法返回两个不相等的值,编译和运行都是不会报错的。不过这样违反了 Java 规范,程序也就埋下了 BUG。 - 规范2:如果
equals()
方法返回false
,即两个对象“不相同”,并不要求对这两个对象调用hashCode()
方法得到两个不相同的数。说的简单点就是:“如果两个对象不相同,他们的 hashCode 可能相同”。
为什么重写 equals() 时总要重写 hashCode()
一个很常见的错误根源在于没有重写 hashCode() 方法。在每个重写了 equals()
方法的类中,也必须重写 hashCode()
方法。如果不这样做的话,就会违反 Object.hashCode 的通用约定,从而导致该类无法结合所有基于散列的集合一起正常运作,这样的集合包括 HashMap、HashSet 和 Hashtable。
- 在应用程序的执行期间,只要对象的
equals()
方法的比较操作所用到的信息没有被修改,那么对这同一个对象调用多次,hashCode()
方法都必须始终如一地返回同一个整数。在同一个应用程序的多次执行过程中,每次执行所返回的整数可以不一致。 - 如果两个对象根据
equals()
方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode()
方法都必须产生同样的整数结果。 - 如果两个对象根据
equals()
方法比较是不相等的,那么调用这两个对象中任意一个对象的hashCode()
方法,则不一定要产生相同的整数结果。但是程序员应该知道,给不相等的对象产生截然不同的整数结果,有可能提高散列表的性能。
总结
equals()
方法用于比较对象的内容是否相等(重写以后);hashCode()
方法只有在集合中用到;- 当重写了
equals()
方法时,比较对象是否相等将通过重写后的equals()
方法进行比较(判断对象的内容是否相等); - 将对象放入到集合中时,首先判断要放入对象的
hashCode()
值与集合中的任意一个元素的hashCode()
值是否相等,如果不相等直接将该对象放入集合中。如果hashCode()
值相等,然后再通过equals()
方法判断要放入对象与集合中的任意一个对象是否相等,如果equals()
判断不相等,直接将该元素放入到集合中,否则不放入。