Java 继承 - 在子类中使用 super.equals() 覆盖超类的 equals 中使用的方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20205268/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 00:16:24  来源:igfitidea点击:

Inheritance - using super.equals() in subclasses that override methods used in equals of superclass

javainheritanceequals

提问by Kuba Spatny

I've been testing a code and stumbled across a problem: Should you call super.equals()method in subclass that can override some of the methods used in equals()method of the super class?

我一直在测试一个代码,偶然发现一个问题:你应该super.equals()在子类中调用可以覆盖equals()超类方法中使用的一些方法的方法吗?

Let's consider the following code:

让我们考虑以下代码:

public abstract class Item {
    private int id;
    private float price;

    public Item(int id, String name, float price, String category) {
        this.id = id;
        this.name = name;
        this.price = price;
        this.category = category;
    }

    public int getID() {
        return id;
    }

    public float getPrice() {
        return price;
    }

    @Override
    public boolean equals(Object object){
        if(object instanceof Item){
            Item item = (Item) object;
            if( id == item.getID()
                && price == item.getPrice())                    
            { return true; }
        }
        return false;
    }
}

And the subclass DiscountedItem:

和子类 DiscountedItem:

public class DiscountedItem extends Item {
    // discount stored in %
    private int discount;

    @Override
    public boolean equals(Object object) {
        if(object instanceof DiscountedItem){
            DiscountedItem item = (DiscountedItem) object;
            return (super.equals(item)
                    && discount == item.getDiscount()
            );
        }
        return false;
    }

    public int getDiscount() {
        return discount;
    }

    @Override
    public float getPrice() {
        return super.getPrice()*(100 - discount);
    }    
}

I've been just re-reading Angelika Langer's secrets of equals(), where she even states:

我一直在重新阅读Angelika Langer 的 equals() 的秘密,她甚至说:

There is agreement that super.equals() should be invoked if the class has a superclass other than Object.

如果该类具有除 Object 之外的超类,则应调用 super.equals() 。

But I think it's highly unpredictable when the subclass will override some of the methods. For instance when I compare 2 DiscountedItemobjects using equals, the super method is called and item.getPrice()is dynamically dispatched to the correct method in the subclass DiscountedItem, whereas the other price value is accessed directly using variable.

但是我认为当子类会覆盖某些方法时,这是非常不可预测的。例如,当我DiscountedItem使用 equals比较 2 个对象时,会调用 super 方法并item.getPrice()动态分派给子类中的正确方法DiscountedItem,而使用变量直接访问另一个价格值。

So, is it really up to me (as I should implement the method correctly) or is there a way around it?

那么,这真的取决于我(因为我应该正确实现该方法)还是有办法解决它?

采纳答案by Matt

Compare instance variables directly rather than comparing an instance variable to its related getter method.

直接比较实例变量,而不是将实例变量与其相关的 getter 方法进行比较。

For example, change

例如,改变

&& price == item.getPrice())

to

&& this.price == item.price)

The getter method is unnecessary since private instance variables are only inaccessible outside the class structure.

getter 方法是不必要的,因为私有实例变量只能在类结构之外访问。



Note:

笔记:

I previously recommended the following:

我之前推荐了以下内容:

&& this.getPrice() == item.getPrice())

While it will work in the question's example, it is not well suited for all cases. Consider if the subclass DiscountedItemdeclared the method getPriceas such:

虽然它可以在问题的示例中工作,但它并不适合所有情况。考虑子类是否如此DiscountedItem声明方法getPrice

@Override
public float getPrice() {
    return Math.floor(super.getPrice());
} 

This would result in the false equivalence:

这将导致错误的等价:

DiscountedItem firstItem = DiscountedItem(1, "", 1.1, "");
DiscountedItem secondItem = DiscountedItem(1, "", 1.0, "");
firstItem.equals(secondItem); // Returns true despite different prices.

回答by Kuba Spatny

Oh my, I guess I just had to post the question to get it..

哦,天哪,我想我只需要发布问题就可以了..

To get rid of the problem, instead of directly accessing variables - call the getters!

为了摆脱这个问题,而不是直接访问变量 - 调用 getter!

@Override
public boolean equals(Object object){
      if(object instanceof Item){
          Item item = (Item) object;
          if( this.getID() == item.getID()
              && this.getPrice() == item.getPrice())                    
          { return true; }
      }
      return false;
}

This code no longer has the problem when overriding methods.

覆盖方法时,此代码不再有问题。

回答by peter.petrov

If you call the equals of the DiscountedItem when can you have a problem? If something is DiscountedItem and something else is Item these two are never equal as per equals. Right? So I don't see a problem if you always call the getters.

如果您调用 DiscountedItem 的 equals,您什么时候会遇到问题?如果某些东西是 DiscountedItem 而其他东西是 Item 这两个永远不会相等。对?所以如果你总是打电话给吸气剂,我看不出有什么问题。

Also, you need to override hashCode if you override equals.

此外,如果您覆盖 equals,则需要覆盖 hashCode。

回答by Floegipoky

The implementation of equalsshould depend on state and type, but not functionality. You went wrong in your base class:

的实现equals应该取决于状态和类型,而不是功能。您在基类中出错了:

@Override
public boolean equals(Object object){
    if(object instanceof Item){ // Type check- good!
        Item item = (Item) object;
        if( id == item.getID()  // Depends on functionality- bad!
            && price == item.getPrice()) // Depends on functionality- bad!                    
        { return true; }
    }
    return false;
}

item.getID()and item.getPrice(), as you've noticed, can be overwritten to break the contract of Item.equals().

item.getID()并且item.getPrice(),正如您所注意到的,可以被覆盖以破坏 的合同Item.equals()

@Override
public boolean equals(Object object){
    if(object instanceof Item){ // Type check- good!
        Item item = (Item) object;
        if( id == item.id  // Depends on state- good!
            && price == item.price)  // Depends on state- good!
        { return true; }
    }
    return false;
}

This will never be broken by a child class. Further, it enables the child to meaningfully delegate to it.

这永远不会被子类打破。此外,它使孩子能够有意义地委托给它。

@Override
public boolean equals(Object object) {
    if(object instanceof DiscountedItem){
        DiscountedItem item = (DiscountedItem) object;
        return (super.equals(item)
                && this.discount == item.discount
        );
    }
    return false;
}

The child only needs to worry about comparing the data that it owns.

孩子只需要担心比较它拥有的数据。