提示十

2022-05-16  本文已影响0人  飞絮搅青冥

今天来看提示十:覆盖equals时需要遵守的通用约定。

当equals没有被覆盖时,比较的是内存中的地址,类的每个实例都只和自身相等,当满足下面条件时,我们不会去覆盖equals方法:

接下来就是重写equals时需要注意的五个原则:

这五点看起来非常直接,我一开始也感觉这些都是理所应当。但是作者介绍了继承和equals的情况后我就有了不一样的想法,难怪父类重写了equals方法后,子类就不推荐重写了。

比如A类有一个属性a,重写了equals只要a相等,那么对象相同。B类继承A,并且多了一个b属性,想当然,它的equals方法就需要比较a,b两个属性。这样做的话,我们就会发现A.equals(B)没有问题,但是B.equals(A)就是false了。如果为了解决这对称性的问题,我们在B的equals方法中进行分类,如果对象是A,那么就只比较a属性,如果对象是B,那么就比较a,b属性,否则就返回false。这样做看似解决了对称性问题,但是当我们引入B1,B2两个不同的B对象,那么就容易得到B1.equals(A),A.equals(B2),但是B1和B2又显然不相同,这样又违反了传递性。所以当我们遇到这种情况时,作者推荐组合而非继承。通过组合的方式可以有效解决这个问题。

试图解决对称性会引入传递性问题

以下是编写高质量 equals 方法的配方:

  1. 使用==操作符检查参数是否为这个对象的引用, 如果是, 则返回true。
  2. 使用instanceof操作符检查参数是否为正确的类型, 如果不是, 则返回false. 注意这个地方不能使用getClass替换instanceof,这样不符合里氏替换原则。
  3. 把参数转换成正确的类型。
  4. 对于该类中的每个关键域, 检查参数中的域是否与该对象中对应的域相匹配。

现在idea等工具都提供了一键生成equals等方法,我以前也用过,但是需要注意equals的格式是可以自己选择的,有时候会生成带有getClass的方法,可能我们需要注意一下。

最后是三条提醒:

  1. 当重写 equals 方法时,同时也要重写 hashCode 方法
  2. 不要让 equals 方法试图太聪明。
  3. equal 时方法声明中,不要将参数 Object 替换成其他类型。因为这样是重载,并不是覆盖重写。应该养成良好的习惯,在覆盖方法的时候加上@Override注解,及时发现这些错误。

总之,除非必须:在很多情况下,不要重写 equals 方法,从 Object 继承的实现完全是你想要的。如果你确实重写了 equals 方法,那么一定要比较这个类的所有重要属性,并且以保护前面 equals 约定里五个规定的方式去比较。

上一篇下一篇

猜你喜欢

热点阅读