传递性,相同类型的传递性出错基本不可能,出错的一般都是写子类扩展属性的情况。
例如两个类
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类型一定不要写错,写错的话就变成重载了,编译正常,运行数据却出错了,半天也不知道哪里出错。
例如两个类
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类型一定不要写错,写错的话就变成重载了,编译正常,运行数据却出错了,半天也不知道哪里出错。