我一直在测试代码并偶然发现了一个问题:你应该在子类中调用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
中的正确方法,而另一个价值值直接访问使用变量。
那么,这真的取决于我(因为我应该正确地实现该方法)还是有办法绕过它?
答案 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。