近日在看Effective Java,以下是对重写equals方法的一些归纳和我的见解。
No need to overwrite
只要满足以下任何一点就不需要重写equals:
1. 创建的类的实例本质上是唯一的,既是object class而不是value class。
2. 不关心类是否提供了“逻辑相等”的功能,用户并不关心对此类创造出来的实例是否相等。
3. 父类已经重写过equals方法,子类只需要继承过来,并且父类的equals方法对子类也是适用的。
4. 类是private或package的,并且确定它的equals方法永远不会被调用。为保险起见,避免这个类的可见性日后发生改变,这种情况下可以让自己的equals方法抛出异常。
Need to overwrite
在这里有必要说一下为什么要重写equals方法:对于我们自己写的类具有一定的逻辑比较意义,而且父类也没有重写equals方法(如果有父类的话),这种类也就是通常我们说的value class,它的实例要比较的是逻辑上的相等(它的某个成员变量或是成员变量的集合),而不是要比较它和另外一个这个类的对象是否是同一个对象。
当重写equals方法时,需要同时满足以下几点:
1. reflexive 自反性,对于x.equals(x)一定为true。
2. symmetric 对称性,x.equals(y)为true,y.equals(x)也一定为true。
3. transitive 传递性,x.equals(y)为true,y.equals(z)为true,x.equals(z)也一定为true。
4. consistent 一致性,如果x,y对象的信息没有改变的情况下,多次调用x.equals(y)应该一直返回true或false。
5. non-nullity 非空性,x.equals(null)一定为false。
具体如何遵守这5条的反例详见Effective Java第7条,相当深刻。
How to overwrite
1. 使用==来检查“实参是否指向对象的同一个引用”。
2. 使用instanceof检查“实参是否为正确的类型”。
3. 将实参转换到正确的类型。
4. 检查实参的对应的成员变量的值是否相等。
5. 一定检查是否满足Need to overwrite的5条准则。
Tip
1. 重写equals的时候,总是要重写hashCode方法。
2. 不要使equals方法依赖于不可靠的资源,如网络。
3. 不要将equals的Object的参数写成其他类型。
以下是一个简单的基本的重写的例子
public class AboutEquals {
private int id;
private String name;
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof AboutEquals)) {
return false;
}
AboutEquals other = (AboutEquals) obj;
if (this.id == other.id && this.name.equals(other.name)) {
return true;
}
return false;
}
}