【笔记】equals方法重写、相等性测试和继承

【笔记】equals方法重写、相等性测试和继承

一、equals方法重写

Object类中的equals方法用于检测两个对象是否相等,默认操作为检测两个对象是否具有相同的引用。在Object的子类中一般覆盖equals方法(比如String类),多用于检测两个对象的状态是否相等。
重写equals方法,一般采取以下步骤:

1
2
3
4
5
6
7
8
9
10
11
12
public booleanequals(Object other){
//如果两个对象具有相同的引用则返回true,这是一条优化
if (this==other) return true;
//如果other为null,返回false
if (other==null) return false;
//如果两个对象不属于同一个类,返回false
if (getClass()!=other.getClass()) return false;
//现在可以确定两个对象属于同一个类,进行类型转换,假设this属于Person类
Person oth=(Person)other;
//依次判断实例域是否相等
return field1.equals(oth.field1)&&(field2==oth.field2);
}

在覆盖equals方法时,必须使方法名和形参列表和父类一致,由方法名和参数列表组成的方法签名在方法重载起到关键作用,意味着以下写法是不允许的

1
2
public boolean equals(Object oth){}
public int equals(Object oth){}

我们可以使用@Override来标记被重写的方法,如果方法没有被成功重写,则会给出错误报告,这是一个有效避免错误的小技巧。
在判断实例域时,当实例域为对象时应该使用Objects.equals方法,以避免空指针异常,比如上面代码最后一行应改为:

1
return Objects.equals(field1,field2)&&(field2==oth.field2);

使用该方法需要导入java.util.Objects,如果两个参数都为null,返回true;如果仅有一个为null,返回false,否则调用

1
para1.equals(para2);

该方法源码实现摘录如下:

1
2
3
4
public static boolean equals(Object a,Object b){
return (a == b) || (a != null && a.equal=s(b));
}

二、相等测试和继承

如果两个参数不属于一个类,问题就会变得复杂。很多人单纯使用instanceof进行测试:

1
if(!(otherinstanceof thisObj)) return false;

不过这么做并没有解决other是thisObj子类的对象的问题,而且违反了equals方法的对称性,Java语言规范要求equals方法的对称性:当且仅当x.equals(y);返回true,y.equals(x);也应该返回true。如果son和父类father共同的域相等且子类中重写了equals方法,按照(一)中的方法,faher.equals(son)会返回true,而son.equals(father)则会返回false,这显然是不合适的。
为了改进这个问题,写出更完美的equals方法,可以进行以下判断:

  • 如果相等的概念由父类决定,可以使用instanceof进行检测,这样还有利于检测由父类派生出的多个子类的对象之间的相等性。
  • 如果相等的概念由子类决定,equals方法的对称性强制使用getClass()进行检测。

在对代码进行修改时,如果相等的概念由子类决定则(一)中代码保持不变。如果相等的概念由父类决定,那么(一)中在判断完other不为null后的第三步改为:

1
if(!(otherinstanceof Person)) return false;


2017.7.31 18:00第一次编辑