第八条:覆盖 equals 时请遵守通用约定
什么时候需要覆盖 equals 方法?类具有自己的逻辑相等概念,并且父类的 equals 方法不能满足需要。
重写 equals 时需要遵循一下约定:
自反性:不知道怎么写能让这个返回 false,如果返回 false 了,那么把结果添加到 Collection 集合类中时,那么 contains 方法就会一直返回 false
对称性:
- class Fifth1 {
- private String s;
- public Fifth1(String s) {
- this.s = s;
- }
- @Override
- public boolean equals(Object o) {
- if (o instanceof Fifth1) {
- return s.equalsIgnoreCase(((Fifth1) o).s);
- }
- if (o instanceof String) {
- return s.equalsIgnoreCase((String) o);
- }
- return false;
- }
- }
- Fifth1 fifth1 = new Fifth1("FZK");
- String s = "fzk";
这两个比较就违反了自反性,fifth1.equals(s) 调用自定义的 equals 方法,s.equals(fifth1) 调用 String 的 equals 方法。
- List list = new ArrayList();
- list.add(fifth1);
- list.contains(s);
然后又有这种代码,结果可能是 true,也可能抛运行时异常。
传递性:
- 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;
- }
- }
- class ColorPoint extends Point {
- private final String color;
- public ColorPoint(int x, int y, String color) {
- super(x, y);
- this.color = color;
- }
- }
ColorPoint 肯定需要一个 equals。
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof ColorPoint) {
- return false;
- }
- return super.equals(obj) && ((ColorPoint)obj).color.equals(color);
- }
- Point p = new Point(1, 1);
- ColorPoint colorPoint = new ColorPoint(1, 1, "red");
这两个比较会失去对称性。
这么写 equals:
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof ColorPoint) {
- return false;
- }
- if (!(obj instanceof ColorPoint)) {
- return obj.equals(this);
- }
- // obj is a ColorPoint
- return super.equals(obj) && ((ColorPoint)obj).color.equals(color);
- }
Point p = new Point(1, 1);
ColorPoint colorPoint1 = new ColorPoint(1, 1,"red");
ColorPoint colorPoint2 = new ColorPoint(1, 1,"blue");
colorPoint1.equals(p);
colorPoint2.equals(p);
colorPoint1.equals(colorPoint2);
比较这三个的时候又会失去传递性。
其实上面的那种设计,没有什么特别好的办法。改变设计框架还能解决上面的问题,第一中办法是将 Color 作为 ColorPoint 的成员。另一种办法是将超类建成抽象类,只要不能直接实例花超类的实例,上面的问题就不会发生。
一致性:相等的永远相等,除非改变了什么。在比较的时候,不要使 equals 依赖不可靠的资源。
非空性:书的作者起的名,指所有的对象和 null 比较的时候都不能返回 true。还有在方法里不能返回 NullpointerException。
在写完一个 equals 方法时一定要考虑是否是对称的,传递的,一致的。自反和非空通常会自动满足。
忠告:
第九条:覆盖 equals 时总要覆盖 hashCode 方法
如果覆盖了 equals 而没有覆盖 hashCode,会违反 Object.hashCode 的通用约定,导致该类无法结合所有基于散列的集合一起正常运作,这样的集合包括 HashMap,HashSet,HashTable。
Object 规范:
第十条:始终要覆盖 toString 方法
第十一条:谨慎地覆盖 clone
地十二条:考虑实现 Comparable
书中太啰嗦,感觉没什么好说的。
来源: