覆盖equals方法

时间:2011-06-15 20:57:24

标签: java override equals

新手问题:

所以在我的大学作业中,我必须为我创建的新类重写对象类equals方法。

新类是“Product”,每个产品都有一个唯一的“id”属性。所以这就是我覆盖它的方式:

@Override
public boolean equals(Object obj) {
       final Product other = (Product) obj;
       if (id != other.id)
           return false;
       return true;
   }

事情是这样做是10分中的1.5分,让我怀疑是那么容易。所以我开始搜索,我找到了类似的东西:

@Override
public boolean equals(Object obj) {
       if (this == obj)
           return true;
       if (obj == null)
           return false;
       if (getClass() != obj.getClass())
           return false;
       final Product other = (Product) obj;
       if (id != other.id)
           return false;
       return true;
   }

对我来说根本没有意义,因为我认为最后一次检查所有其他的ifs限制。你们有什么想法?哪种方法可以覆盖这种方法?

谢谢!

5 个答案:

答案 0 :(得分:14)

第二段代码更好:

  • 优化x.equals(x),这对于正确性不是必需的,但是是有帮助的优化
  • 它可以应对x.equals(null)而不是投掷NullPointerException
  • 它处理一个完全不同的类的对象,而不会抛出你想要的ClassCastException(例如x.equals("foo")
  • 它需要 exact 相同类型才能提供对称关系;否则obj.equals(x)可以调用不同的方法,给出不同的结果。

答案 1 :(得分:2)

第二个版本是安全的,我会说一个迂腐的版本。相反,您的版本可以启动ClassCastException,因为您假设变量obj的运行时类型是product类型。这不是真的,这就是你应该使用this.getClass() != obj.getClass()的原因(你也可以用instanceof运算符来解决这个问题。)

如果我这样做

Product p = new Product();
p.equals("abc");

我得到一个例外,我应该false

此外,它还管理product.equals(null)问题,该问题应返回false,如文档中equals合同方法中所述。如果你不关心这个并且你这样做,你内心就等于:

...
Product p = (Product)obj; // obj is null
obj.id // this throws a NullPointerException

答案 2 :(得分:1)

覆盖equals()时使用的常用习语是

@Override
public boolean equals(Object obj) {
       if (! (obj instanceof Product) ) return false;

       final Product other = (Product) obj;
       if (id != other.id)
           return false;
       return true;
   }

在您发布的第二个版本中:

  • 第一个if()可能有用 仅在以下情况下进行优化 支票太贵了。但 情况并非如此,所以这只是 多余的代码,这是邪恶的。
  • 如果您定义Product子类,那么该版本将无效 不会改变方法equals()的语义。 (例如,一个类 提供一些方便的方法但是 没有额外的内部状态 对象。)这是因为 第三个if()。

答案 3 :(得分:0)

第2号是 Effective Java 的最佳选择,用于覆盖equals的最安全方法。如果Object为null并且它没有尽可能优化(不检查ojb是否是对自身的引用),则1具有nullpointer

答案 4 :(得分:0)

'Joshua Bloch:Effective Java'提出的解决方案是(假设Product没有除Object以外的超类):

@Override
public boolean equals(Object obj) {
    if (this == obj) return true;
    if (!(obj instanceof Product)) return false;
    final Product other = (Product) obj;
    if (id != other.id) return false;
    return true;
}

您的第一个解决方案有两个缺点:

  • new Product(1).equals(null)抛出NullpointerException,尽管在Object.equals()中指定它返回false。
  • new Product(1).equals(new Vector())抛出ClassCastException但指定在Object.equals()中返回false。

通过实例检查可以解决这两个问题。 if (this == obj) return true;通常对提高效率很有用,但在这里可能没有必要。

您发布的第二个解决方案使编写具有良好语义的Product的子类变得困难。如果你有一个子类

public class SubProduct extends Product {
    SubProduct(int id) {
         super(id);
    }
    ...
}

您将拥有!new Product(4).equals(new SubProduct(4))。这违反了Liskov的嫌疑原则,并且通常被认为不太好。如果你有一个最后的课程 第二种解决方案与上述相同。