第三章:对于所有对象都通用的方法。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     @Override
17     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      * 后一种总是返回false
17      */
18     @Override
19     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     @Override
53     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 方法。众所周知,&&操作符是有短路原则的,因此应该将最有可能不相同和比较开
   销更低的域比较放在最前面。

时间: 2024-08-09 18:48:44

第三章:对于所有对象都通用的方法。ITEM8:覆盖equals时请遵守通用约定。的相关文章

覆盖equals时请遵守通用约定——Effective Java 读书笔记

如果满足了以下任一条件,这就正是所期望的结果: 类的每个实例本质上都是唯一的. 不关心类是否提供了"逻辑相等"的测试功能. 超类已经覆盖了equals,从超类继承过来的行为对于子类也是适合的. 类是私有的或是包级私有的,可以确定它的equals方法永远不会被调用. 如果类具有自己特有的"罗吉相等"概念(不同于对象等同的概念),而且超类还,没有覆盖equals以实现期望的行为,这时我们就需要覆盖equals方法. equals方法实现了等价关系: 自反性 对称性 传递

第八条:覆盖equals时请遵守通用约定

==是物理相等 equals是逻辑相等 因为每个类的实例对象本质上都是唯一的 ,利用物理相等(==)是指一个实例只能相等于它自己. 利用逻辑相等是(equals)指 一个实例是否和另一个实例的某些关键域相等,从而来判断这两实例是否相等. Object类的equals方法的实现:物理相等的话就逻辑相等. 什么时候不需要覆盖Object类的equals方法? 1.希望这个类的实例只能和自身相等,不覆盖equals方法,只继承Object类的equals方法. 我们比较这个类的实例对象是否相等,无论是

24、覆盖equals时请遵守通用约定

覆盖equals方法看似很简单,但是有许多覆盖方式会导致错误,并且后果非常严重.最容易的避免这类问题的方法就是不覆盖equals方法,这种情况下,每个实例都与它自身相等. 如果你必须覆盖equals方法,那么请遵循: 1.自反性.对于任何非null的引用值x,x.equals(x)必须返回true: 2.对称性.对于任何非null的引用值x和y,当且进党y.equalts(x)返回true时,x.equals(y)必须返回true: 3.传递性.对于任何非null的引用值x和y和z,如果x.eq

第10项:重写equals时请遵守通用约定

??重写equals方法看起来似乎很简单,但是有许多重写方式会导致错误,而且后果非常严重.最容易避免这类问题的办法就是不覆盖equals方法,在这种情况下,类的每个实例都只能与它自身相等.如果满足了以下任何一个条件,那就是正确的做法: 类的每个实例都是唯一的. 对于代表活动实体而不是值(value)的类来说确实如此,例如Thread.Object提供的equals实现对这些类具有完全正确的行为(The equals implementation provided by Object has ex

[Effective Java 读书笔记] 第三章 对所有对象都通用的方法 第八 ---- ?条

这一章主要讲解Object类中的方法, Object类是所有类的父类,所以它的方法也称得上是所有对象都通用的方法 第八条 覆盖equals时需要遵守的约定 Object中的equals实现,就是直接对对象进行相等的比较: public boolean equals(Object obj) { return (this == obj); } 那么什么时候需要覆盖equals呢? 当你的类有自己的逻辑相等,而不是对象相等时,应该自己实现equals,比如Date和Interger,他们的相等比较不仅

effective java-读书笔记-第三章 对于所有对象都通用的方法

个人博客同步发布:effective java-读书笔记-第三章 对于所有对象都通用的方法 第三章 对于所有对象都通用的方法 所有非final方法(equals.hashCode.toString.clone.finalize)都有明确的通用约定,因为它们被设计成是要被覆盖的,如果不遵守,基于散列的集合(HashMap.HashSet.HashTable)可能无法结合该类一起运作. 第8条 覆盖equals时请遵守通用约定 覆盖equals规范: 自反性(reflexive).对于任何非null

Effective Java读书笔记——第三章 对于所有对象都通用的方法

第8条:覆盖equals时请遵守通用的约定 设计Object类的目的就是用来覆盖的,它所有的非final方法都是用来被覆盖的(equals.hashcode.clone.finalize)都有通用约定. 首先看看equals方法: 若满足下面的这些情况中的某一个,您可以直接使用Object类中的equals方法而不用覆盖: 类的每个实例本质上是唯一的.对于那些代表实例而不是值的类来说可以不用覆盖equals方法.比如Thread类.因为每一个Thread类的实例都表示一个线程,这与Thread某

Effective Java读书笔记——第三章 对于全部对象都通用的方法

第8条:覆盖equals时请遵守通用的约定 设计Object类的目的就是用来覆盖的,它全部的非final方法都是用来被覆盖的(equals.hashcode.clone.finalize)都有通用约定. 首先看看equals方法: 若满足以下的这些情况中的某一个,您能够直接使用Object类中的equals方法而不用覆盖: 类的每个实例本质上是唯一的.对于那些代表实例而不是值的类来说能够不用覆盖equals方法.比方Thread类.由于每个Thread类的实例都表示一个线程,这与Thread某些

Effective java 第三章对于所有对象都通用的方法(一) 读书笔记

对于所有对象都通用的方法 覆盖equals时请遵守通用约定 类的每个实例本质上都是唯一的. 不关心类是否提供了逻辑相等的测试功能 超类已经覆盖了equals,从超类继承过来的行为对于子类也是合适的. 类是私有的或是包级私有的,可以确定它的equals方法永远不会被调用. throw new AssertionError() 一般覆盖Object.equals都是值类 但有一种值类不需要覆盖equals方法,即实例受控,确保每个值至多只存在一个对象的类.如枚举 覆盖equals方法,通用约定. 自