首页 > 学院 > 开发设计 > 正文

第八条 覆盖equals请遵守通用的约定(二)

2019-11-06 07:36:26
字体:
来源:转载
供稿:网友
传递性,相同类型的传递性出错基本不可能,出错的一般都是写子类扩展属性的情况。例如两个类public class Point {    PRivate int x;    private int y;    public Point(int x, int y) {        this.x = x;        this.y = y;    }    public int getY() {        return y;    }    public void setY(int y) {        this.y = y;    }    public int getX() {        return x;    }    public void setX(int x) {        this.x = x;    }    @Override    public boolean equals(Object o) {        if(o == this){            return true;        }        if(o instanceof Point){            Point p = (Point) o;            return p.x == x && p.y==y;        }        return false;    }}public class ColorPoint extends Point {    private int color;    public ColorPoint(int x, int y,int color) {        super(x, y);        this.color = color;    }}如果不提供equals方法,直接使用父类的方法,那么比较时,颜色的值会被忽略掉,假若自己添加一个有颜色的比较,  @Override    public boolean equals(Object o) {        if(!(o instanceof ColorPoint)){            return false;        }        return super.equals(o) && ((ColorPoint)o).color == color;            }这样做的效果和前一章 刚开始的String和CaseString有异曲同工之妙的错误。那就是Point p1 = new Point(1,2);ColorPoint p2 = new ColorPoint(1,2,Color.RED);p1.equals(p2)值为true,p2.equals(p1)的值为false,对称性失效。此时,如果用instanceof对类型进一步判断,确定是Point 或者ColorPoint类型,分开判断,则可以解决这个问题。由于Point是父类,所以如果不属于父类,那么也肯定不是子类型。 @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 p3 = new ColorPoint(1,2, Color.BLUE); p1.equals(p2)  p1.equals(p3)都为true,此时 p3.equals(p2)却是false。一个解决方法是根据类型判断,如果是非类型,则为false,在Point里面equals方法中加入getClass()方法代替instanceof关键字。但又会引起另外一个问题,java讲究的是扩展,继承,此时子类一些操作就没法用了,就像effective中举的例子。那怎么办?用哪种方法,此时可以使用复合模式。public class ColorPoint {    private int color;    private Point point;    public ColorPoint(int x, int y,int color) {        point = new Point(x,y);        this.color = color;    }    public Point aspoint(){        return point;    }    @Override    public boolean equals(Object o) {        if(!(o instanceof ColorPoint)){            return false;        }        ColorPoint cp = (ColorPoint) o;        return cp.point.equals(point) && cp.color == color;    }}不使用继承方法,用复合,相当于在Point的外面包裹了一层,这样就解决了一些难题。复合的好处就是可以在ColorPoint 中直接通过asPoint()返回一个Point进行数据的比较和使用。大家在使用对象前,一般都会做非空判断,此时可以用instanceof关键字代替,它在进行对象格式校验时,已经做了类型判断。equals方法,可以使用一些小窍门来提高效率。1、使用 == 来做比较,这个直接比较的就是地址值,速度最快。2、使用instanceof 作类型判断,如果不是同一个类型,那就不用继续比较了。3、参数转换为正确的类型。4、对每个属性进行检查,对于float 和 double要注意,int类型可以直接用==,String类型用equals,对象的话就递归调用equals吧。正确的使用 && 和 || ,少用三元表达式。最后书中也提出了三个告诫:1、覆盖equals时也要覆盖hashCode方法,下一篇介绍。2、不要使equals太过智能,这个能解决大部分问题就行。3、重写equals方法,equals(Object o)里面的参数Object类型一定不要写错,写错的话就变成重载了,编译正常,运行数据却出错了,半天也不知道哪里出错。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表