在Java中,==和equals的区别,以及重写equals()方法还要重写hashCode()方法
1. ==和equals的区别?
- 对于基本类型
==判断两个值是否相等,基本类型没有equals()方法
- 对于引用类型
== 判断两个变量是否引用同一个对象,
对于没有重写的equals()方法,比较的是引用类型的变量所指向的对象的地址;
对于重写的equals()方法,比较的是所指向的对象的内容
equals()源码解析
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* String} object that represents the same sequence of characters as this
* object.
*
* @param anObject
* The object to compare this {@code String} against
*
* @return {@code true} if the given object represents a {@code String}
* equivalent to this string, {@code false} otherwise
*
* @see #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
从源码中知道,equals()方法存在于Object类中,因为Object类是所有类的直接或间接父类,也就是说所有的类中的equals()方法都继承自Object类,而通过源码我们发现,Object类中equals()方法底层依赖的是==,那么,在所有没有重写equals()方法的类中,调用equals()方法其实和使用==的效果一样,也是比较的地址值,然而,Java提供的所有类中,绝大多数类都重写了equals()方法,equals方法进行了重写则是用来比较指向的对象所存储的内容是否相等。
2. 重写equals()方法为什么还要重写hashCode()方法
hashCode()
hashCode() 返回散列值,而 equals() 是用来判断两个对象是否等价。等价的两个对象散列值一定相同,但是散列值相同的两个对象不一定等价。
在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法,保证等价的两个对象散列值也相等。
下面的代码中,新建了两个等价的对象,并将它们添加到 HashSet 中。我们希望将这两个对象当成一样的,只在集合中添加一个对象,但是因为 EqualExample 没有实现 hasCode() 方法,因此这两个对象的散列值是不同的,最终导致集合添加了两个等价的对象。
EqualExample e1 = new EqualExample(1, 1, 1);
EqualExample e2 = new EqualExample(1, 1, 1);
System.out.println(e1.equals(e2)); // true
HashSet<EqualExample> set = new HashSet<>();
set.add(e1);
set.add(e2);
System.out.println(set.size()); // 2
举个例子,比如将对象添加到HashSet中,HashSet会先计算对象的hashCode中来判断对象添加的位置,同时也会与该位置其他已经加入的对象的hashCode值进行比较,如果没有相符合的hashCode,那么该对象就没有出现;但是如果有相同的hashCode值的对象,就会调用equals方法来比较hashCode值相等的对象是否相等。如果hashCode值相等且对象相等,就不会重复添加对象;如果hashCode值相等且对象不相等,就会重新散列其他位置。
比如上面代码中,判断对象相等后,对象相同,equals方法会被覆盖,也就是会被重写,所以对象存在哈希表的位置也会改变,重新赋予对象在哈希表中的位置。如果equals方法重写了,不重写hashCode方法,对象是根据hashCode的存储地址形成的一个哈希值,就会造成相同的对象散列到不同位置(正确的应该是相同的对象散列相同的位置)造成地址不能覆盖的问题。
3. 总结
hashCode()和equals()的联系
(1)如果两个对象相等,则hashCode一定是相等的。
对象相等:对象的内容相等,且指向同一个位置地址
(2)两个对象相等,调用equals方法返回的是true
分为两种情况:
<1>类重写了equals方法,比较的是内容相等,但是对象相等hashCode值一定是相同的。
<2>类没有重写equals方法,比较的是对象的地址已经相等,内容也相等,所以是返回的true
(3)两个对象有相同的hashCode值,他们不一定相同
因为hashCode值只是确保地址相同,不一定是对象的内容相等。
(4)所以equals方法如果被重写,hashCode方法也必须被重写,否则造成地址不统一的问题