覆盖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限制。 你们有什么想法?哪种更好的方法来覆盖这种方法?

谢谢!

第二段代码更好:

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

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

如果我做

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

我得到一个例外而我应该变得false

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

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

用于覆盖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()。

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

‘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的嫌疑原则,并且通常被认为不太好。 如果您有最终类,则第二个解决方案与上述相同。