继承关系下的equals改写
来源:互联网 发布:如何使用数据有效性 编辑:程序博客网 时间:2024/05/21 10:13
本作品采用知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议 进行许可。
学习过Java的人都知道,Java对象的内容比较依靠的是Object类的equals方法。改写这个方法有严格的要求,JDK API中是这样描述的:
public boolean equals(Object obj);指示其他某个对象是否与此对象“相等”。
equals 方法在非空对象引用上实现相等关系:
- 自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。
- 对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 也一定返回 true。
- 传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 也一定返回 true。
- 一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。
- 对于任何非空引用值 x,x.equals(null) 一定返回 false。
注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
Josh Bloch在Effective Java一书中介绍了一种通用的改写equals的方法,Apache Commons Lang库也为我们提供了两个工具类来简化改写equals与hashCode的过程。关于这一点请参考利用Commons Lang库改写equals与hashCode方法一文。
具有继承关系的对象比较
五大特性中的对称性与传递性是其中比较麻烦的两个,特别是当我们要进行子类对象与父类对象的内容比较时。如下面的例子:
父类代码(Point类)
子类代码(ColorPoint类)
枚举型Color
当你想要对Point与ColoredPoint两种对象进行内容比较时,上述代码将会违反对称性原则。测试代码如下:
那么,如何才能正确比较两个具有继承关系的对象呢?
Josh Bloch的解决方案
Josh Bloch在Effective Java一书中提供的解决方案是:复合优先于继承。也就是避开了继承问题,使ColorPoint与Point之间没有继承关系,进而完全不可比。ColorPoint类的改造如下:
两种对象的比较结果均为false,测试代码如下:
Josh Bloch为我们提供了避免错误的方法,但没有解决我们提出的问题!
Martin Odersky的解决方案
与Josh Bloch的解决方案相对应,Martin Odersky、Lex Spoon与Bill Venners三人在合作完成的How to Write an Equality Method in Java 一文中提出了另一个解决方案:canEqual 方法。此文的中文版可查看酷壳翻译整理的如何在Java中避免equals方法的隐藏陷阱 。本质上这个方案提供一个判断函数,判断哪些对象可以与本类对象进行比较。
据此,Point类的实现如下:
ColorPoint类的实现如下:
测试过程如下:
Martin的方案很好的解释了为什么ColorPoint对象不能与Point对象进行比较,但这似乎并不能解决如何才能让ColorPoint对象与Point对象进行比较的问题。利用canEqual是否可以完成这一目的呢?
补充说明
在这里提供另一个类ColorPointEx,实现了可以与所有继承自Point的对象进行比较的功能。并且比较是有选择的:如果比较的对象也是继承自ColorPointEx,则比较的内容包括Color信息;如果比较的对象是继承自 Point,则比较的内容不包括Color信息。ColorPointEx的代码实现如下:
测试代码如下:
可以说,Martin的canEqual方案可以解决继承关系下的对象比较问题,但前提是你必须正确的使用它。
- 继承关系下的equals改写
- 继承关系下的hashCode改写
- String的equals方法改写
- Object改写之前和改写之后(如String和tostring)的==和equals的关系
- View下的继承关系
- 改写equals时遵守的约定
- 改写equals与hashCode的简单方法
- 继承关系下的构造器风云
- java 继承时方法的改写
- 7-在改写equals的时候请遵守通用约定
- 改写equals 方法时请遵守的约定
- Java-改写equals方法必须遵循的准则
- 在改写equals的时候请遵守general contract
- Effective Java笔记之改写equals的通用约定
- Effective Java——Item8:改写equals的时候总是要改写hashCode
- 改写equals时总是要改写hashCode
- Java-改写equals 必须改写hashChode()
- Equals()和HashCode()的关系
- 细说 repoze.bfg 中的 view
- 在 repoze.bfg 中使用json传递数据
- 详解 repoze.bfg traversal
- 通过a4j:jsFunction 调用原生的javascript方法,并且共享和传递后台bean里面的变量
- MS SQL Server日期计算
- 继承关系下的equals改写
- 100以内的质因数分解并计算完全平方数
- 新年喜获三大奖项
- delphi 组件的安装
- ecshop 函数列表
- hibernate里load方法和get方法的区别
- Windows 2003下mountvol命令使用方法
- DSP程序优化方法(1)
- 细线表格CSS