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

时间:2013-11-25 23:01:15

标签: java inheritance equals

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

让我们考虑以下代码:

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;
    }
}

子类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);
    }    
}

我刚刚重新阅读Angelika Langer's secrets of equals(),她甚至说:

  

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

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

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

4 个答案:

答案 0 :(得分:4)

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

例如,更改

&& price == item.getPrice())

&& this.price == item.price)

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


注意:

我之前推荐过以下内容:

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

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

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

这会导致错误的等价:

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

答案 1 :(得分:2)

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;
}
正如您所注意到的,{p> 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;
}

子课程永远不会打破这种情况。此外,它使孩子能够有意义地委托给孩子。

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

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

答案 2 :(得分:1)

哦,我想,我只是想发布问题才能得到它......

要解决问题,而不是直接访问变量 - 请调用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;
}

重写方法时,此代码不再存在问题。

答案 3 :(得分:0)

如果您在遇到问题时调用DiscountedItem的等号? 如果某些东西是DiscountedItem而其他东西是Item这两个 永远不等于等于。对?所以如果你我没有看到问题 总是打电话给吸气鬼。

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