在处理inheritance时重写equals方法

我一直在阅读在处理子类时如何最好地覆盖equals方法,在这里我发现了不少post。 他们建议使用instanceof或getClass()来实现解决方案的不同方法来比较不同子类的对象。

但是参考Effective Java,我的理解是(我是新手,所以我可能错了!)Bloch认为最终两者都有问题,“没有办法扩展可实例化的类并添加一个值组件,同时保留等于合同,除非你愿意放弃面向对象抽象的好处“。 然后建议“赞成合成而非inheritance”。

所以我正在处理这个类层次结构:AbstractClass,ConcreteClass1和ConcreteClass2。 ConcreteClass1扩展了AbstractClass,ConcreteClass2扩展了ConcreteClass1。 目前只有AbstractClass重写了equals方法。

所以在AbstractClass中:

public abstract class AbstractClass { private String id; public boolean equals(Object other) { return other != null && other.getClass().equals(getClass()) && id.equals(((AbstractClass) other).id); } } 

在ConcreteClass1我有:

 public class ConcreteClassOne extends AbstractClass { private final AbstractClass parent; public ConcreteClassOne( String anId, AbstractClass aParent ) { super( anId ); parent = aParent; } } 

最后在ConcreteClassTwo中我有:

 public class ConcreteClassTwo extends ConcreteClassOne { private static int nextTrackingNo = 0; private final int trackingNo; public ConcreteClassTwo ( String anId ) { super( anId, null ); trackingNo= getNextTrackingNo(); } } 

所以我认为我需要在ConcreteClassOne和ConcreteClassTwo中重写equals方法以包含有效字段parent和trackingNo。 我不允许更改设计,因此使用合成不是一种选择。 有什么建议么?

最简单的方法是在具体类和抽象类中扩展equals()。

 public class ConcreteClassTwo extends ConcreteClassOne { public boolean equals(Object other) { boolean rv = super.equals( other ); if ( other instanceof ConcreteClassTwo ) { rv = rv && (this.trackingNo == ((ConcreteClassTwo) other).trackingNo); } return rv; } } 

如果在ConcreteClassOneConcreteClassTwoequals ,那么equals的对称性就会被破坏:

 Object c1 = new ConcreteClassOne(), c2 = new ConcreteClassTwo(); System.out.println("c1=c2? " + c1.equals(c2)"); System.out.println("c2=c1? " + c2.equals(c1)"); 

现在,如果你按照通常的方式实现equals ,那就打印了

 true false 

因为在c2.equals你有一个instanceof ConcreteClassTwo ,它对于c1失败了,但是在相反的情况下,类似的检查通过了。

基类契约应该指定两种方法之一:要么声明没有派生类对象应该将自己视为不是完全相同的类的任何其他对象,要么它应该指定每个派生类对象应该是可转换为由基类契约定义的规范forms,如果它们的规范forms匹配,则应将两个不可变对象视为等效对象。

后一种情况的一个例子是ImmutableSquareFloatMatrix基类,其方法是int GetSize()float GetCell(int row, int column) 。 一个常见的实现将包含一个(size * size)浮点值数组,但也可以有一个例如ZeroMatrixIdentityMatrix类,其唯一字段指定大小, ConstantMatrix类具有指定大小的字段和指定值的字段应该为每个单元格返回一个DiagonalMatrix类,其中一维数组只包含对角线的项目( GetCell方法将为其他所有内容返回零),等等。

给定从ImmutableSquareFloatMatrix派生的两个类实例,可以通过比较它们的大小然后比较其中的所有值来比较它们,但在许多情况下这将是低效的。 如果被比较的任何一个对象“知道”另一个对象的类型,则可能极大地提高效率。 如果两个对象都不知道另一个对象,则回退到默认比较方法可能会很慢,但在任何情况下都会产生正确的结果。

处理这种情况的可行方法可能是让基类型实现一个equals2方法,如果它对另一个对象的特殊知识意味着它可以告诉它是相等的,则返回1,如果它可以告诉它不相等则返回-1,或者0,如果它无法分辨。 如果任何一种类型的equals2方法都知道它们是不相等的,那么它们就是不相等的。 否则,如果他们知道他们是平等的,他们是平等的。 否则,使用逐个单元格比较测试相等性。