1. 背景
String a=new String("123");
String b=new String("123");
我们知道,在java中 a == b
比较的是对象的在内存中的物理地址,equals()
方法的作用本来和==
相同,也是比较两者的物理地址,但String
类重写了equals()
方法,于是String
类的equals
方法变成了比较两个字符串对象的字符串内容是否相等。
2. equals()
和hashcode()
方法需要同时重写的原因
首先,我们要明白hashCode()
方法的作用是确定对象在散列存储结构例如HashMap
、HashSet
中的存储地址。
注:这个地址不是对象在内存中的真实存储地址,只是在数据结构中的逻辑地址
那么,我们就能知道为什么重写equals()
方法同时要重写hashcode()
方法了:
因为,如果重写了equals()
方法,没有重写hashCode()
方法的话,如果a.equals(b)
,但a的hashCode
与b的hashCode
不相等,则当我们将a、b同时加入散列存储结构map、set
时,就可能出现数据结构中存在两个值相等的对象的情况,从而导致混淆。
示例:
String a=new String("123");
String b=new String("123");
System.out.println(a==b); //false
System.out.println(a.equals(b)); //true
System.out.println(a.hashCode()==b.hashCode()); //true
Set<String>set=new HashSet<>();
set.add(a);
System.out.println(set.contains(b)); //true
以上例子可以看出,虽然a
和b
不是同一个对象,但是由于表达式a.equals(b)
结果是true
,所以a的hashCode
与b的hashCode
相等,两者在set
中存储地址相同,在set
中加入a
后,在set
中查询b
,返回结果是true
。如果仅重写了equals方法,而没有重写hashcode方法,那就有可能出现a.equals(b)==ture
,但是set.contais(b)
返回的却是false
;
综上,重写equals()方法同时尽量也要重写hashcode()方法。
3. 重写equals
方法遵循的原则
hashCode
并不需要唯一性,但equals
必须严格地判断两个对象是否相同。
正确的equals
方法有如下特性:
- 自反性:
x.equals(x)
一定返回true
- 对称性:如果
x.equals(y)
为true
,那么y.equals(x)
也为true
- 传递性:如果
x.equals(y)
为true
、y.equals(z)
为true
,那么x.equals(z)
也为true
- 一致性:如果
x
和y
中用于等价比较的信息没有改变,那么x.equals(y)
无论调用多少次,结果都一致 - 任何不是
null
的x
,x.equals(null)
一定返回false
4. equals与hashCode的相关规定
之所以有规定,是为了使诸如HashMap
这样的哈希表正常使用。具体规定如下:
equals
相等,hashcode
一定相等。equals
不等,hashcode
不一定不等。hashcode
不等,equals
一定不等。hashcode
相等,equals
不一定相等。