【问题标题】:What does equals(Object obj) do?equals(Object obj) 有什么作用?
【发布时间】:2020-05-07 00:34:39
【问题描述】:

我经常在不同的地方找到一种 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;
    }
}

【问题讨论】:

标签: java


【解决方案1】:

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

默认情况下(在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(..)

检查the javadoc 以获取equals(..) 方法所需的确切合同。

在许多情况下,当覆盖 equals(..) 时,您还必须覆盖 hashCode()(使用相同的字段)。这也在 javadoc 中指定。

【讨论】:

    【解决方案2】:

    不同的类对于使 2 个对象“相等”的标准不同。通常情况下,equals() 如果是同一个 Object,则返回 true:

    Object a = new Object();
    Object b = new Object();
    return(a.equals(b));
    

    这将返回 false,尽管它们都是“对象”类,但它们不是同一个实例。 a.equals(a) 将返回 true。

    但是,在像字符串这样的情况下,您可以有 2 个不同的实例,但字符串相等是基于组成这些字符串的文字字符:

    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”,但第二个不会因为“example”不是“another”。

    你不需要为每个类重写 equals(),只有当有特殊情况下相等时,比如一个包含 3 个字符串的类,但只有第一个字符串用于确定相等性。在您发布的示例中,可能有另一个字段 description 对于 2 个不同的“联系人”可能不同,但如果这 4 个条件匹配(名字/姓氏和家庭/手机号码),而描述匹配或不匹配不会影响2个联系人是否相等。

    【讨论】:

      【解决方案3】:

      除了 Bozho 给出的所有内容之外,如果覆盖 equals,还有一些额外的事情需要注意:

      • something.equals(null) 必须始终返回 false - 即 null 不等于其他任何东西。此要求在您的代码的第二个 if 中得到处理。

      • 如果 something == something else 是真的,那么 something.equals(something else) 也必须为真。 (即相同的对象必须相等)您的代码的第一个 if 负责处理此问题。

      • .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()。 IE。两个相等的对象的哈希码必须相同。请注意,相反的情况并非如此:具有相同哈希码的两个对象可能彼此相等,也可能不相等。通常,通过从用于确定对象相等性的相同属性派生 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,从而使您免于繁琐且可能容易出错的工作。

      【讨论】:

        【解决方案4】:

        equals 方法用于当人们想知道两个对象是否根据对象认为合适的定义等价。例如,对于String 对象,等价是关于两个对象是否表示相同的字符串。因此,类通常会提供自己的 equals 实现,这种实现方式对于该类来说是自然的。

        equals方法与==不同之处在于后者测试对象身份,即对象是否相同(不一定等同于等价)。

        【讨论】:

          【解决方案5】:

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

          看到这个:Overriding the java equals() method quirk

          【讨论】:

            【解决方案6】:

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

            即a.equals(a);总是返回真。

            如果我们要提供自己的实现,那么我们将使用某些步骤来实现对象相等。

                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) 应该返回 假的。

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

            【讨论】:

              【解决方案7】:

              还有一件事,map 使用 equals 方法来决定 Object 是否作为键存在。 https://docs.oracle.com/javase/8/docs/api/java/util/Map.html

              【讨论】:

                猜你喜欢
                • 2014-09-03
                • 1970-01-01
                • 2012-12-07
                • 1970-01-01
                • 2014-01-05
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多