equals(Object obj)方法是做什么用的?

13

我经常在不同的地方看到一个equals方法。它实际上是做什么的?我们必须在每个类中都有这个方法吗?

   public boolean equals(Object obj)
    {
    if (obj == this)
    {
        return true;
    }
    if (obj == null)
    {
        return false;
    }
    if (obj instanceof Contact)
    {
        Contact other = (Contact)obj;
        return other.getFirstName().equals(getFirstName()) &&
                other.getLastName().equals(getLastName()) &&
                other.getHomePhone().equals(getHomePhone()) &&
                other.getCellPhone().equals(getCellPhone());

    }
    else
    {
        return false;
    }
}

4
我假设你已经查看了文档,它已经很清楚地阐述了:http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html [向下滑动到equals(),因为在评论中直接链接似乎无效]。 - NPE
7个回答

34

它重新定义了对象的“相等”。

默认情况下(在java.lang.Object中定义),只有当两个对象是同一实例时,它们才相等。但是,您可以在覆盖它时提供自定义相等逻辑。

例如,java.lang.String通过比较内部字符数组来定义相等性。这就是为什么:

String a = new String("a"); //but don't use that in programs, use simply: = "a"
String b = new String("a");
System.out.println(a == b); // false
System.out.println(a.equals(b)); // true

即使您可能不需要像那样测试相等性,但您使用的类需要。例如,List.contains(..)List.indexOf(..)的实现使用.equals(..)
请查看javadoc以获取equals(..)方法所需的确切契约。
在许多情况下,当重写equals(..)时,您还必须重写hashCode()(使用相同的字段)。这也在javadoc中指定。

12

不同的类对于什么使两个对象“相等”的标准有不同的定义。通常,equals()会在它们是同一个对象时返回true:

Object a = new Object();
Object b = new Object();
return(a.equals(b));
尽管它们都是“Object”类,但它们不是同一个实例,因此这将返回false。 a.equals(a) 将返回true。
但是,在像字符串这样的情况下,你可以有两个不同的实例,但是字符串的相等性基于构成这些字符串的文字字符。
String a = new String("example");
String b = new String("example");
String c = new String("another");
a.equals(b);
a.equals(c);
这些都是不同的String实例,但第一个equals会返回true,因为它们都是"example",但第二个equals不会因为"example"不等于"another"。
你不需要为每个类覆盖equals()方法,只有当存在特殊情况需要考虑相等时,才需要覆盖。比如一个包含3个字符串的类,但仅使用第一个字符串来确定相等性。在你发布的示例中,可能会有另一个字段"description",这个字段对于两个不同的"Contacts"可能是不同的,但是只要这4个条件匹配(名字、姓氏以及家庭/手机号码),那么2个"Contacts"将被视为相等,而描述是否匹配并不影响2个"Contacts"是否相等。

10

除了Bozho提供的所有内容,如果要重写equals方法还有一些额外需要注意的事项:

  • something.equals(null) 必须始终返回false——即null不等于其他任何对象。您的代码的第二个if已经处理了此要求。

  • 如果 something == something else 为真,则something.equals(something else)也必须为真。(即相同的对象必须相等)您的代码的第一个if已经处理了这个问题。

  • 对于非null对象,.equals应当是对称的,即a.equals(b)应该与b.equals(a)相同。有时,如果您正在子类化并覆盖父类和子类中的equals方法,则此要求会被打破。通常,equals方法包含诸如if (!getClass().equals(other.getClass())) return false;的代码,至少可以确保不同类型的对象不相等。

  • 如果您重写了equals方法,则还必须重写hashCode方法,使以下表达式成立:if (a.equals(b)) assert a.hashCode() == b.hashCode()。即相互之间相等的两个对象的哈希码必须相同。请注意,反之未必成立:具有相同哈希码的两个对象可能相等,也可能不相等。通常,从用于确定对象相等性的相同属性派生hashCode可以满足此要求。

在您的情况下,hashCode方法可以是:

public int hashCode() {
  return getFirstName().hashCode() +
    getLastName().hashCode() +
    getPhoneHome().hashCode() +
    getCellPhone().hashCode();
}
  • 如果你实现了 Comparable 接口比较两个对象的大小,a.compareTo(b) == 0 应当仅在 a.equalTo(b) == true 时成立。

许多IDE(例如Eclipse,IntelliJ IDEA,NetBeans)都提供自动生成equalshashCode方法的功能,这样可以避免你繁琐且可能出错的工作。


3
< p > equals 方法用于判断两个对象是否相等,根据对象的定义可以有不同的判断标准。例如,对于 String 对象,相等意味着两个对象表示的是相同的字符字符串。因此,类通常提供自己的 equals 实现,以适应该类的自然方式。

equals 方法与 == 不同,后者测试对象的身份,即对象是否相同(这不一定与相等相同)。


1

它使您能够重新定义哪些对象是相等的,哪些不是,例如,您可以定义如果应用程序中的逻辑相同,则两个Person对象相等,如果Person.ID相同或Weight相等。

请参见:覆盖java equals()方法的怪异行为


0

0

默认情况下,当我们没有为自定义类提供实现时,Object类的equals方法会被调用。Object类的equals方法使用引用比较对象。

例如,a.equals(a); 总是返回true。

如果我们要提供自己的实现,则需要对对象的相等性采取某些步骤。

    Reflexive:  a.equals(a) always returns true;

    Symmetric: if a.equals(b) is true then b.equals(a) should also be true.

    Transitive: If a.equals(b), b.equals(c) then a.equals(c) should be true/false according to previous 2 result.

    Consistent: a.equals(b) should be the same result without modifying the values of a and b.

注意:默认的equals方法检查引用,即==运算符。
注意:对于任何非空引用值a,a.equals(null)应返回false。
public class ObjectEqualExample{

     public static void main(String []args){
        Employee e1 = new Employee(1, "A");
        Employee e2 = new Employee(1, "A");

        // if we are using equals method then It should follow the some properties such as Reflexive, Symmetric, Transitive, and constistent
        /* 
        Reflexive:  a.equals(a) always returns true;
        Symmetric: if a.equals(b) is true then b.equals(a) should also be true.
        Transitive: If a.equals(b), b.equals(c) then a.equals(c) should be true/false according to previous 2 result.

        Consistent: a.equals(b) should be the same result without modifying the values of a and b.

        Note: default equals method check the reference i.e. == operator.
        Note: For any non-null reference value a, a.equals(null) should return false
        */
        System.out.println(e1.equals(e1));
        System.out.println(e1.equals(e2));
     }
}

class Employee {
    private int id;
    private String name;

    @Override
    public String toString() {
        return "{id ="+id+", name = "+name+"} ";
    }

    @Override
    public boolean equals(Object o) {
        // now check the referenc of both object
        if(this == o) return true;

        // check the type of class
        if(o == null || o.getClass() != this.getClass()) return false;

        // now compare the value
        Employee employee = (Employee)o;
        if(employee.id == this.id && employee.name.equals(this.name)) {
            return true; 
        } else return false;
    }

    public int hashCode() {
         // here we are using id. We can also use other logic such as prime number addition or memory address.
        return id;
    }

    public Employee(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接