重写equals方法需要遵循三条主要约定:
1、对称性:A.equals(B)=true则B.equals(A)=true。
2、传递性:A.equals(B)=true,B.equals(C)=true则A.equals(C)=true。
3、一致性:A.equals(B)=ture,则一直保持不变。
点Point对象:
static class Point{
private final int x;
private final int y;
public Point(int x,int y)
{
this.x=x;
this.y=y;
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof Point))
{
return false;
}
Point p=(Point)obj;
return p.x==x&&p.y==y;
}
}
彩色点ColorPoint对象:
static class ColorPoint extends Point{
private int x;
private int y;
private final Color color;
public ColorPoint(int x,int y,Color color)
{
super(x,y);
this.color=color;
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof ColorPoint))
{
return false;
}
ColorPoint p=(ColorPoint)obj;
return p.x==x&&p.y==y&&p.color==color;
}
}
这两个对象都重写了equals方法,看似没有什么问题但是它们违反了对称性和传递性:
public static void main(String[] args) {
Point p1=new Point(1,2);
ColorPoint p2=new ColorPoint(1,2,Color.red);
ColorPoint p3=new ColorPoint(1,2,Color.blue);
System.out.println(p1.equals(p2));//违反对称性
System.out.println(p2.equals(p1));
System.out.println(p1.equals(p2));//违反传递性
System.out.println(p1.equals(p3));
System.out.println(p2.equals(p3));
}
运行结果:
true
false
true
true
false
这个例子没有遵循约定所以从道理上也讲不通,p1.euqals(p2)=true,而p1没有颜色却和p2有色点相同,make no sense.
问题就出在了instanceof上面,因为obj instanceof Class,当obj是Class的实例或者子类的实例就返回true,作出如下修改即可,对就是用getClass():
Point:
static class Point{
private final int x;
private final int y;
public Point(int x,int y)
{
this.x=x;
this.y=y;
}
@Override
public boolean equals(Object obj) {
if(obj==null||obj.getClass()!=getClass())
{
return false;
}
Main.Point p=(Main.Point) obj;
return p.x==x&&p.y==y;
}
}
ColorPoint:
static class ColorPoint extends Point{
private int x;
private int y;
private final Color color;
public ColorPoint(int x,int y,Color color)
{
super(x,y);
this.color=color;
}
@Override
public boolean equals(Object obj) {
if(obj==null||obj.getClass()!=getClass())
{
return false;
}
Main.ColorPoint p=(Main.ColorPoint)obj;
return p.x==x&&p.y==y&&p.color==color;
}
}
再次执行刚才的比较:
public static void main(String[] args) {
Point p1=new Point(1,2);
ColorPoint p2=new ColorPoint(1,2,Color.red);
ColorPoint p3=new ColorPoint(1,2,Color.blue);
System.out.println(p1.equals(p2));
System.out.println(p2.equals(p1));
System.out.println(p1.equals(p2));
System.out.println(p1.equals(p3));
System.out.println(p2.equals(p3));
}
运行结果:
false
false
false
false
false
这个结果就满足对称性和传递性了。
至于第三点,上面的例子显然满足一致性,它不会随时间而改变结果。重写equals方法时,要记住不要使equals方法依赖于不可靠(可变)的资源就不会违反一致性了。