首页 > 代码库 > 第三章:对于所有对象都通用的方法。ITEM8:覆盖equals时请遵守通用约定。
第三章:对于所有对象都通用的方法。ITEM8:覆盖equals时请遵守通用约定。
1、什么时候需要覆盖equals?如果类具有自己特有的“逻辑相等”概念,而且超类还没有覆盖equals。
2、覆盖equals时需要遵守的约定:
- 自反性。对于任何非null的引用值x,x.equals(x)必须返回true。
- 对称性。对于任何非null的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)必须返回true。
1 package com.twoslow.cha3; 2 3 /** 4 * 对称性 5 */ 6 public class CaseInsensitiveString { 7 8 private final String s ; 9 10 public CaseInsensitiveString(String s) {11 if(s == null)12 throw new NullPointerException() ; 13 this.s = s ; 14 }15 16 @Override17 public boolean equals(Object o) {18 /*19 * String类中的方法并不知道CaseInsensitiveString类型的字符串,总是返回false,违反了对称性20 * if(o instanceof CaseInsensitiveString)21 return s.equalsIgnoreCase(((CaseInsensitiveString)o).s) ;22 if(o instanceof String)23 return s.equalsIgnoreCase(((String)o)) ;24 */25 /**26 * 把与String互操作的代码去掉27 */28 return (o instanceof CaseInsensitiveString) && ((CaseInsensitiveString)o).s.equalsIgnoreCase(s) ;29 }30 31 }
- 传递性。对于任何非null的引用值x、y、z,如果x.equals(y)返回true,并且y.equals(z)返回true,则x.equals(z)必须返回true。
1 package com.twoslow.cha3; 2 3 import java.awt.Color; 4 5 public class ColorPoint extends Point{ 6 7 private final Color color ; 8 9 public ColorPoint(int x, int y,Color color) {10 super(x,y) ;11 this.color = color ; 12 }13 14 /**15 * 在比较普通点和有色点,或者相反的情况时,前一种忽略了颜色16 * 后一种总是返回false17 */18 @Override19 public boolean equals(Object o) {20 if(!(o instanceof ColorPoint))21 return false ;22 return super.equals(o) && ((ColorPoint)o).color == color ;23 }24 25 }26 27 28 package com.twoslow.cha3;29 30 import java.awt.Color;31 32 /**33 * 复合优先于继承34 */35 public class ColorPoint02{36 37 private final Point point ;38 private final Color color ; 39 40 public ColorPoint02(int x, int y,Color color) {41 if(color == null)42 throw new NullPointerException() ;43 point = new Point(x,y) ;44 this.color = color ; 45 }46 //提供一个视图方法返回内部的 Point 对象实例。这里 Point 实例为 final 对象非常重要,47 //可以避免使用者的误改动。视图方法在 Java 的集合框架中有着大量的应用。48 public Point asPoint() {49 return point ;50 }51 52 @Override53 public boolean equals(Object o) {54 if(!(o instanceof ColorPoint02))55 return false ;56 ColorPoint02 other = (ColorPoint02) o ;57 return other.point.equals(point) && other.color.equals(color) ;58 }59 }
- 一致性。对于任何非null的引用值x和y,只要equals的比较操作在对象中所用的信息没有被修改,多次调用x.equals(y)就会一致地返回true,或者一致返回false。
- 对于任何非null的引用值x,x.equals(null)必须返回false。
1 @Override public boolean equals(Object o) { 2 if (o == null) 3 return false; 4 if (!(o instanceof MyType)) 5 return false; 6 } 7 8 // 注意以上代码中的 instanceof 判断,由于在后面的实现中需要将参数 o 进行类型强转,如果类型不 9 // 匹配则会抛出 ClassCastException,导致 equals 方法提前退出。在此需要指出的是 instanceof 还有一10 // 个潜在的规则,如果其左值为 null,instanceof 操作符将始终返回 false,因此上面的代码可以优化为:11 @Override public boolean equals(Object o) {12 if (!(o instanceof MyType))13 return false;14 }
鉴于之上所述,该条目中给出了重载 equals 方法的最佳逻辑:
1.使用==操作符检查"参数是否为这个对象的引用",如果是则返回 true。由于==操作符是基于对象地址的比较,因此特别针对拥有复杂比较逻辑的对象而言,这是一种性能优化的方式。
2.使用 instanceof 操作符检查"参数是否为正确的类型",如果不是则返回 false。
3.把参数转换成为正确的类型。由于已经通过 instanceof 的测试,因此不会抛出ClassCastException 异常。
4.对于该类中的每个"关键"域字段,检查参数中的域是否与该对象中对应的域相匹配。
5.如果域字段为 Object 对象,则使用 equals 方法进行两者之间的相等性比较,如果为 int 等整型基本类型,可以直接比较,如果为浮点型基本类型,考虑到精度和 Double.NaN
和 Float.NaN 等问题,推荐使用其对应包装类的 compare 方法,如果是数组,可以使用 JDK 1.5 中新增的 Arrays.equals 方法。众所周知,&&操作符是有短路原则的,因此应该将最有可能不相同和比较开
销更低的域比较放在最前面。
第三章:对于所有对象都通用的方法。ITEM8:覆盖equals时请遵守通用约定。
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。