-- Start
重写 equals 方法是一件很令人头疼的事情, Java 语言规范要求 equals 方法具有下面的特性:
1. 自反性: x.equals(x)应该返回true.
2. 对称性: 如果x.equals(y)返回true, 那么y.equals(x)也应该返回true.
3. 传递性: 如果x.equals(y)返回true, y.equals(z)返回true, 那么x.equals(z)也应该返回true.
4. 一致性: 如果对象没有变化, 反复调用equals方法应该返回相同的结果.
5. x.equals(null) 应该返回false.
看上去很简单, 但是在涉及继承的时候, 稍有不慎就违反了对称性, 下面是一个例子.
public class Test {
public static void main(String[] args) {
Poeple p = new Poeple();
p.setName("ZhangSan");
p.setAge(20);
Student s = new Student();
s.setName("ZhangSan");
s.setAge(20);
s.setID(1);
System.out.println("p.equals(s) == " + p.equals(s));
System.out.println("s.equals(p) == " + s.equals(p));
}
}
class Poeple {
private String name;
private int age;
@Override
public boolean equals(Object otherObject) {
if (this == otherObject)
return true;
if (otherObject == null)
return false;
if (!(otherObject instanceof Poeple))
return false;
Poeple other = (Poeple) otherObject;
return name.equals(other.name) && age == other.age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class Student extends Poeple {
private int ID; // 学号
@Override
public boolean equals(Object otherObject) {
if (!super.equals(otherObject))
return false;
if (!(otherObject instanceof Student))
return false;
Student other = (Student) otherObject;
return ID == other.ID;
}
public int getID() {
return ID;
}
public void setID(int iD) {
ID = iD;
}
}
结果如下:
p.equals(s) == true
s.equals(p) == false
出现这种情况的原因是超类与子类有不同的比较规则, 实际的情况有以下两种:
1. 由超类决定是否相等, 如: 不管是学生还是老师, 每个人都有身份证号, 由身份证号来确定两个人是否是同一个人, 下面是一个范例程序.
class Poeple {
private int ID;
private String name;
// 由于超类决定是否相等, 可以将equals方法设置为final, 禁止子类重写
@Override
public final boolean equals(Object otherObject) {
if (this == otherObject)
return true;
if (otherObject == null)
return false;
if (!(otherObject instanceof Poeple))
return false;
Poeple other = (Poeple) otherObject;
return ID == other.ID;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getID() {
return ID;
}
public void setID(int iD) {
ID = iD;
}
}
class Student extends Poeple {
// Student 可以有自己的域
}
class Teacher extends Poeple {
// Teacher 可以有自己的域
}
2. 子类有自己的相等概念, 下面是一个范例程序.
class Poeple {
private String name;
private int age;
@Override
public boolean equals(Object otherObject) {
if (this == otherObject)
return true;
if (otherObject == null)
return false;
if (getClass() != otherObject.getClass()) // 注意此处, 我们不能通过 instanceof 来判断
return false;
Poeple other = (Poeple) otherObject;
return name.equals(other.name) // 使用 equals 对象域
&& age == other.age; // 使用 == 比较基本类型
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class Student extends Poeple {
private int grade;
@Override
public boolean equals(Object otherObject) {
if (!super.equals(otherObject)) // 此处需要调用父类的 equals 方法
return false;
Student other = (Student) otherObject;
return grade == other.grade;
}
}
从上面的例子可以看出, 想写出一个完美的 equals 还是很不容易的, 幸运的是 Apache Common 包有个 EqualsBuilder 类, 它能帮助我们很容易的实现 equals 方法.
--更多参见:Java 精萃
-- 声 明:转载请注明出处
-- Last Updated on 2012-05-18
-- Written by ShangBo on 2012-05-18
-- End