hashCode()和equals()方法可以说是Java完全面向对象的一大特色.它为我们的编程提供便利的同时也带来了很多危险.这篇文章我们就讨论一下如何正解理解和使用这2个方法.
如何重写equals()方法
- It is reflexive: for any non-null reference value
x
,x.equals(x)
should returntrue
. - It is symmetric: for any non-null reference values
x
andy
,x.equals(y)
should returntrue
if and only ify.equals(x)
returnstrue
. - It is transitive: for any non-null reference values
x
,y
, andz
, ifx.equals(y)
returnstrue
andy.equals(z)
returnstrue
, thenx.equals(z)
should returntrue
. - It is consistent: for any non-null reference values
x
andy
, multiple invocations ofx.equals(y)
consistently returntrue
or consistently returnfalse
, provided no information used inequals
comparisons on the objects is modified. - For any non-null reference value
x
,x.equals(null)
should returnfalse
.
这段话用了很多离散数学中的术数.简单说明一下:
class Coder {
private String name;
private int age; // getters and setters
}
我们想要的是,如果2个程序员对象的name和age都是相同的,那么我们就认为这两个程序员是一个人.这时候我们就要重写其equals()方法.因为默认的equals()实际是判断两个引用是否指向内存中的同一个对象,相当于 == . 重写时要遵循以下三步:
if(other == this)
return true;
if(!(other instanceof Coder))
return false;
Coder o = (Coder)other;
return o.name.equals(name) && o.age == age;
看到这有人可能会问,第3步中有一个强制转换,如果有人将一个Integer类的对象传到了这个equals中,那么会不会扔ClassCastException呢?这个担心其实是多余的.因为我们在第二步中已经进行了instanceof 的判断,如果other是非Coder对象,甚至other是个null, 那么在这一步中都会直接返回false, 从而后面的代码得不到执行的机会.
如何重写hashCode()方法
hashCode
method whenever this method(equals) is overridden, so as to maintain the general contract for the hashCode
method, which states that equal objects must have equal hash codes."@Override
public int hashCode() {
int result = 17;
result = result * 31 + name.hashCode();
result = result * 31 + age; return result;
}
String
object is computed as
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
using int
arithmetic, where s[i]
is the ith character of the string, n
is the length of the string, and ^
indicates exponentiation. (The hash value of the empty string is zero.)"
重写equals()而不重写hashCode()的风险
Coder c1 = new Coder("bruce", 10);
Coder c2 = new Coder("bruce", 10);
1 @Override
2 public boolean equals(Object other) {
3 System.out.println("equals method invoked!");
4
5 if(other == this)
6 return true;
7 if(!(other instanceof Coder))
8 return false;
9
10 Coder o = (Coder)other;
11 return o.name.equals(name) && o.age == age;
12 }
Set<Coder> set = new HashSet<Coder>();
set.add(c1);
再执行:
System.out.println(set.contains(c2));
我们期望contains(c2)方法返回true, 但实际上它返回了false.
我让hashCode()每次都返回一个固定的数行吗
@Override
public int hashCode() {
return 10; }