为什么要覆盖equals函数
Object对象自带equals方法,但其是根据对象是否一致来判断相等,但每个对象都是唯一的,所以自带的equals方法只能与其自身相等。
当需要根据对象的成员值是否相等来判断对象是否相等时,就需要复写equals函数了。
equals函数需要遵循的原则
- 自反性
x.equals(x) == true
- 对称性
x.equals(y) == y.equals(x);
- 传递性
x.equals(y) == y.equals(z) == x.equals(z);
- 一致性
- 非空性
在属性没有被修改时,
x.equals(y)的值不应该会发生改变。
常见错误
1.违反对称性
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 cs = new CaseInsensitiveString("a");
String s = "a";
cs.equals(s);// true
s.equals(cs);// false
解决方法是去掉与String交互那部分
@Override
public boolean equals(Object o){
if(o instanceof CaseInsensitiveString)
return s.equalsIgnoreCase(((CaseInsensitiveString) o).s);
return false;
}
2.违反传递性
public class Point{
public int x;
public int y;
........
@Override
public boolean equals(Object o){
if( !(o instanceof Point))
return false;
if(o.x == x && o.y == y)
return true;
return false;
}
}
增加颜色属性
public class ColorPoint extends Point{
public int color;
.....
@Override
public boolean equals(Object o){
if(!(o instanceof Point))
return false;
if(!(o instanceof ColorPoint)
return o.equals(this);
return super.equals(o) && ((ColorPoint)o).color == color;
}
以上代码,虽然保证了对称性,但传递性有错误
ColorPoint p1 = new ColorPoint(1,2,1);
Point p2 = new Point(1,2);
ColorPoint p3 = new ColorPoint(1,2,2);
p1.equals(p2)//true
p2.equals(p3)//true
p1.equals(p3)/false
解决方案:通过复合替代继承,并放弃混合比较
public class ColorPoint{
public Point poin;
public int color;
public Point asPoint(){
return point;
}
@Override
public boolean equals(Object o ){
if(!(o instanceof ColorPoint))
return false;
return (ColorPoint)o.point.equals(point) && (ColorPoint)o.color == color;
}
}
3.非空性
如果不做处理可能会报出空指针错误
@Override
public boolean equals(Object o){
if( o == null)
return false;
}
4.注意事项
复写equals方法的同时,一定要复写hashCode方法,不然会导致HashMap等涉及到哈希数据结构的错误。