当前位置: 首页 > 知识库问答 >
问题:

在处理继承时重写equals方法

贝钧
2023-03-14

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

然而,关于有效的Java,我的理解是(我对这一点还不熟悉,所以我很可能是错的!)布洛赫认为,最终两者都会有问题,“除非你愿意放弃面向对象抽象的好处,否则没有办法在保留equals契约的同时扩展一个可实例化类并添加一个价值组件”。然后建议“重组合轻继承”。

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

所以在课堂上:

public abstract class AbstractClass {
        private String id;


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

    }

在第1课中,我有:

public class ConcreteClassOne extends AbstractClass
{
  private final AbstractClass parent;

  public ConcreteClassOne( String anId, AbstractClass aParent )
  {
    super( anId );

    parent = aParent;
  }

}

最后,在第二课中,我有:

public class ConcreteClassTwo extends ConcreteClassOne
{
  private static int nextTrackingNo = 0;

  private final int trackingNo;

  public ConcreteClassTwo ( String anId )
  {
    super( anId, null );

    trackingNo= getNextTrackingNo();
  }
}

所以我认为我需要重写ConcreteClassOne和ConcreteClassII中的equals方法,以包括有效字段parent和trackingNo。我不允许改变设计,所以不能使用合成。有什么建议吗?

共有3个答案

曾洲
2023-03-14

基类契约应该指定两种方法中的一种:要么声明派生类对象不应该将其自身考虑到不属于完全相同类的任何其他对象,否则它应该指定每个派生类对象应该可转换为基类契约定义的规范形式,如果两个不可变对象的标准形式匹配,则应将其视为等效对象。

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

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

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

翟卓君
2023-03-14

如果在ConcreteClassOneConcreteClassTwo中都有equals,那么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失败,但在相反的情况下,类似的检查通过。

巫马英豪
2023-03-14

最简单的方法是在具体类和抽象类中扩展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;
    }
}
 类似资料:
  • “编写一个名为clsWorker的超类和子类clsHourlyWorker和clssalariedworker。每个工人都有一个名字和一个工资率。编写计算每个员工周薪的方法computePay(int hours)。小时工按实际工作小时数获得小时工资,如果小时数最多为40小时。如果小时工工作超过40小时,则按时间半支付超出部分。受薪工人得到40小时的小时工资,无论实际小时数是多少。为继承编写一个测

  • 问题内容: 我有两个课,和。它们看起来像这样: 此错误指向Field的: 我希望首先调用Background init ()。要将“ a,b”传递给Fields的 init (),Field会分配a和b,然后将其中包含三个0的列表分配给field。然后让Background的 init ()继续,然后调用它自己的buildField()并用包含c的列表覆盖self.field。 似乎我还没有完全理

  • 我创建了一个(个人、学生、员工、教职员工)类。Person必须将Student和Employee分为子类。Employee有两个子类:教员和职员。我已经完成了所有的编码,他们工作得很好,除了我的驱动程序类TestPerson程序给出了编译错误 注:一个测试程序,创建一个人、学生、员工、教职员工,并调用他们的toString方法。 驱动程序类TestPerson的错误。以下是java:- **我只是

  • 如何/可以重写来自非继承类的方法?其次,有没有比“非继承类”更好的术语? 我有一个“扩展”JFrame的类,需要从JPanel重写paintComponent。怎么做?或者它可以扩展JPanel,并需要访问方法,如setTitle()、setResizable()和setDefaultCloseOperation();

  • 本文向大家介绍hashCode 与 equals ?为什么重写equals时必须重写hashCode方法?相关面试题,主要包含被问及hashCode 与 equals ?为什么重写equals时必须重写hashCode方法?时的应答技巧和注意事项,需要的朋友参考一下 面试官可能会问你:“你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode方法?” ha

  • 使用标准代理,我能够截获对equals()方法的调用并执行我的逻辑。问题是这类代理不能强制转换到原始类。 似乎唯一的方法是重写CGLIB库中的一些类。这似乎不是个好主意。