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
xandy,x.equals(y)should returntrueif and only ify.equals(x)returnstrue. - It is transitive: for any non-null reference values
x,y, andz, ifx.equals(y)returnstrueandy.equals(z)returnstrue, thenx.equals(z)should returntrue. - It is consistent: for any non-null reference values
xandy, multiple invocations ofx.equals(y)consistently returntrueor consistently returnfalse, provided no information used inequalscomparisons 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;2. 使用instanceof运算符判断 other 是否为Coder类型的对象.if(!(other instanceof Coder))
return false;3. 比较Coder类中你自定义的数据域,name和age,一个都不能少.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;
}其中int result = 17你也可以改成20, 50等等都可以.看到这里我突然有些好奇,想看一下String类中的hashCode()方法是如何实现的.查文档知:
String object is computed as
usings[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
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);假定我们已经重写了Coder的equals()方法而没有重写hashCode()方法:
@Override
public boolean equals(Object other) {
System.out.println("equals method invoked!");
if(other == this)
return true;
if(!(other instanceof Coder))
return false;
Coder o = (Coder)other;
return o.name.equals(name) && o.age == age;
}然后我们构造一个HashSet,将c1对象放入到set中:
Set<Coder> set = new HashSet<Coder>();
set.add(c1);再执行:
System.out.println(set.contains(c2));我让hashCode()每次都返回一个固定的数行吗
@Override
public int hashCode() {
return 10;
}如果这样的话,HashMap, HashSet等集合类就失去了其 "哈希的意义".用<Effective Java>中的话来说就是,哈希表退化成了链表.如果hashCode()每次都返回相同的数,那么所有的对象都会被放到同一个bucket中,每次执行查找操作都会遍历链表,这样就完全失去了哈希的作用.所以我们最好还是提供一个健壮的hashCode()为妙.
190



被折叠的 条评论
为什么被折叠?



