java 重写equals方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6364258/
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-10-30 15:35:27  来源:igfitidea点击:

Override equals method

javaoverridingequals

提问by I?aki

newbie question here:

新手问题在这里:

So in my university homework I have to override the object class equals method for a new class created by me.

因此,在我的大学作业中,我必须为我创建的新类覆盖对象类的 equals 方法。

The new class is "Product", each product has an "id" attribute which is unique. So this is how I Overrided it:

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

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

The thing is that doing this is 1,5 points out of 10 and it made me suspicius to be that easy. So i started searching and I found things like:

问题是,这样做是 1.5 分(满分 10 分),这让我怀疑如此简单。所以我开始搜索,我发现了类似的东西:

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

Which don't make sense for me at all, because I think that the last if check all the other ifs restrictions. What do you guys think?Which is the better way to Override this method?

这对我来说根本没有意义,因为我认为最后一个 if 检查所有其他 ifs 限制。你们怎么看?覆盖这个方法的更好方法是什么?

Thanks!

谢谢!

回答by Jon Skeet

The second piece of code is better:

第二段代码更好:

  • It optimizes for x.equals(x), which isn't necessary for correctness, but is a helpful optimization
  • It copes with x.equals(null)instead of throwing NullPointerException
  • It handles objects of a completely different class without throwing a ClassCastExceptionwhich yours would (e.g. x.equals("foo"))
  • It requires the exactsame type to provide a symmetric relationship; otherwise obj.equals(x)could invoke a different method, giving a different result.
  • 它优化了x.equals(x),这对于正确性不是必需的,但是是一个有用的优化
  • 它应付x.equals(null)而不是扔NullPointerException
  • 它处理一个完全不同的类的对象,而不会抛出ClassCastException你会(例如x.equals("foo")
  • 它需要完全相同的类型来提供对称关系;否则obj.equals(x)可能会调用不同的方法,给出不同的结果。

回答by Hyman

The second version is a safe one, I would say a pedantic one. Your version, instead, could launch a ClassCastExceptionbecause you are assuming that the runtime type of the variable objis of type product. Which is not true, that's why you should use this.getClass() != obj.getClass()(you could solve this problem also with instanceofoperator).

第二个版本是一个安全的版本,我会说是一个迂腐的版本。相反,您的版本可能会启动 a,ClassCastException因为您假设变量的运行时类型obj是产品类型。事实并非如此,这就是您应该使用的原因this.getClass() != obj.getClass()(您也可以使用instanceof操作员解决此问题)。

If I do

如果我做

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

I get an exception while I should get false.

我得到了一个例外,而我应该得到false.

In addition it manages the product.equals(null)problem, which should return false as stated in equalscontract method in documentation. If you don't care about this and you do, inside you equals:

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

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

回答by ignis

The common idiom used in overriding equals() is

用于覆盖 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;
   }

In the second version that you posted:

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

  • the first if() may be good for optimization only if the following checks are too much expensive. But this is not the case, so that is just redundant code which is evil.
  • That version won't work if you define a Product subclass which does not change the semantics of method equals(). (For example a class which provides some convenience method but no additional internal state to the objects.) This is because of the third if().
  • 第一个 if() 可能只有在以下检查过于昂贵时才有利于优化。但事实并非如此,所以这只是多余的代码,这是邪恶的。
  • 如果您定义了一个不改变方法 equals() 语义的 Product 子类,那么该版本将不起作用。(例如,一个类为对象提供了一些方便的方法,但没有额外的内部状态。)这是因为第三个 if()。

回答by Christoph Zenger

The solution suggested by 'Joshua Bloch: Effective Java' is (assuming that Productdoes not have a superclass other than Object):

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

Your first solution suffers from two drawbacks:

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

  • new Product(1).equals(null)throws a NullpointerException although it is specified to return false in Object.equals().
  • new Product(1).equals(new Vector())throws a ClassCastException although it is specified to return false in Object.equals().
  • new Product(1).equals(null)尽管在 Object.equals() 中指定返回 false,但仍会引发 NullpointerException。
  • new Product(1).equals(new Vector())尽管在 Object.equals() 中指定返回 false,但会抛出 ClassCastException。

Both of these are remedied by the instance check. The if (this == obj) return true;is often useful for efficiency, but probably not necessary here.

这两种情况都可以通过实例检查来补救。这if (this == obj) return true;通常对提高效率很有用,但在这里可能没有必要。

The second solution you posted makes it difficult to write a subclass of Product with good semantics. If you have a subclass

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

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

you will have !new Product(4).equals(new SubProduct(4)). This violates Liskov's susbstitution principle and is often believed to be not so good. If you have a final class the second solutions is the same as the above.

你会有!new Product(4).equals(new SubProduct(4))。这违反了 Liskov 的替代原则,通常被认为不太好。如果您有期末课程,则第二个解决方案与上述相同。

回答by nsfyn55

Number 2 is right out of Effective Javafor the safest way to override equals. 1 has a nullpointer if Object is null and it isn't as optimized as it could be(doesn't check if ojb is a reference to itself)

数字 2 是Effective Java中最安全的覆盖 equals 的方法。1 有一个空指针,如果 Object 为空并且它没有尽可能优化(不检查 ojb 是否是对自身的引用)