在覆盖equals方法的时候,你必须遵守它的通用约定,那么什么时候应该覆盖Object.equals方法呢,如果类具有自己特有的“逻辑相等”概念(不同于对象相同的概念),而且超类还没有覆盖equals以实现期望的行为,这是我们就需要覆盖equals方法。这通常属于“值类”的情形
约定一:自反性(reflexivity)
第一个要求仅仅说明对象必须等于其自身。很难想象会无意识地违反这一条。假如违背了这一条,然后把该类的实例添加到集合中,该集合contains方法会果断的告诉你,该集合不包含你刚添加的这个实例
对称性(symmetry)
例如y.equals(x)返回true 则x.equals(y) 同样返回true
public final class CaseInsensitiveString {
private final String s;
public CaseInsensitiveString(String s){
if(s == null){
throw new NullPointerException();
}
this.s = s;
}
@Override
public boolean equals(Object o) {
if(o instanceof CaseInsensitiveString){
return s.equalsIgnoreCase(((CaseInsensitiveString) o).s);
}
if(o instanceof String){
return s.equalsIgnoreCase((String)o);
}
return false;
}
}
这是一个不区分大小写的字符串,在这个类中,equals方法的意图很好,它企图与普通字符串进行互操作。假设我们有一个不区分大小写的字符串和一个普通的字符串
CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
String s = "polish";
boolean result = cis.equals(s);
正如我们所预期,result为true 但是 String类中的equals方法并不知道忽略大小写,所以
s.equals(cis) 返回的是false。假设你把不区别大写的字符串放到list中
List<CaseInsensitiveString> list = new ArrayList<>() ;
list.add(cis);
此时 list.contains(s);会返回什么结果呢? 没人知道。一旦违反了equals约定,当其他对象面对你的对象的时候,完全不知道这些对象的行为会是什么样,那么如何才能修正这个约定呢,只需要把企图与String互操作的这段代码去掉就行了
public boolean equals(Object o) {
return o instanceof CaseInsensitiveString && s.equalsIgnoreCase(((CaseInsensitiveString) o).s);
}