第四章 java中的hashcode()和equals()方法


这些方法可以在 Object 类中找到,因此可用于所有 java 类。使用这两种方法,可以从 Hashtable、HashMap 或 HashSet 中存储或检索对象。

  • hashcode()
  • equals()

hashcode() 和 equals() 方法

hashcode()

您可能知道,如果您将条目放入 HashMap,首先计算哈希码,然后此哈希码用于查找存储桶(索引),该条目将存储在hashMap 中。如果你不覆盖 hashcode 方法,它将返回内存地址的整数表示。

equals():

当你想定义两个对象之间的相等性时,你必须重写 equals 方法。如果您不覆盖此方法,它将检查引用相等(==),即两个引用是否引用相同的对象

让我们覆盖 hashcode() 和 equals() 的默认实现:

您不必总是重写这些方法,但是假设您想根据名称定义国家对象的相等性,那么您需要重写 equals 方法,如果您要重写 equals 方法,您也应该重写 hashcode 方法。下面的例子将清楚。

让我们借助示例来看看。我们有一个名为 Country 的类

1.Country.java

package org.arpit.java2blog;

public class Country {

    String name;
    long population;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public long getPopulation() {
        return population;
    }
    public void setPopulation(long population) {
        this.population = population;
    }

}

这个国家类有两个基本属性——名称和人口。

现在创建一个名为“EqualityCheckMain.java”的类

package org.arpit.java2blog;

public class EqualityCheckMain {

    /**
     * @author arpit mandliya
     */
    public static void main(String[] args) {

        Country india1=new Country();
        india1.setName("India");
        Country india2=new Country();
        india2.setName("India");
        System.out.println("Is india1 is equal to india2:" +india1.equals(india2));
    }

}

当你运行上面的程序时,你会得到以下输出

Is india1 is equal to india2:false

在上面的程序中,我们创建了两个不同的对象并将它们的名称属性设置为“india”。

因为引用 india1 和 india2 都指向不同的对象,所以默认实现 equals 检查 ==,equals 方法返回 false。在现实生活中,它应该返回 true,因为没有两个国家可以有相同的名称。

如果两个国家的名称相同,现在让我们覆盖 equals 并返回 true。

将此方法添加到上述国家/地区类:

@Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Country other = (Country) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

现在再次运行 EqualityCheckMain.java

您将获得以下输出:

Is india1 is equal to india2:true

现在这是因为如果两个国家名称相同,则覆盖的 equals 方法返回 true。 这里要记住一件事,equals 方法的签名应该与上面相同。

让我们把这个 Country 对象放在 hashmap 中:

在这里,我们将使用 Country 类对象作为键,并将其大写名称(字符串)作为 HashMap 中的值。

package org.arpit.java2blog;

import java.util.HashMap;
import java.util.Iterator;

public class HashMapEqualityCheckMain {

    /**
     * @author Arpit Mandliya
     */
    public static void main(String[] args) {
        HashMap<Country,String> countryCapitalMap=new HashMap<Country,String>(); 
        Country india1=new Country();
        india1.setName("India");
        Country india2=new Country();
        india2.setName("India");

        countryCapitalMap.put(india1, "Delhi");
        countryCapitalMap.put(india2, "Delhi");

        Iterator countryCapitalIter=countryCapitalMap.keySet().iterator();
        while(countryCapitalIter.hasNext())
        {
            Country countryObj=countryCapitalIter.next();
            String capital=countryCapitalMap.get(countryObj);
            System.out.println("Capital of "+ countryObj.getName()+"----"+capital);

        }
    } 
}

当您运行上述程序时,您将看到以下输出:

Capital of India----Delhi
Capital of India----Delhi

现在您一定想知道即使两个对象相等,为什么 HashMap 包含两个键值对而不是一个。这是因为 First HashMap 使用哈希码来查找该键对象的存储桶,如果哈希码相同,则仅检查 equals 方法,因为以上两个国家对象的哈希码使用默认的哈希码方法,两者都有不同的内存地址,因此有不同的哈希码。

现在让我们覆盖哈希码方法。将以下方法添加到 Country 类

@Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

现在再次运行 HashMapEqualityCheckMain.java

您将看到以下输出:

Capital of India----Delhi

所以现在上面两个对象 india1 和 india2 的哈希码是相同的,所以两者都将指向同一个桶,现在将使用 equals 方法比较它们,这将返回 true。 这就是 java doc 说“如果你覆盖 equals() 方法,那么你必须覆盖 hashCode() 方法”的原因

hashcode() 和 equals() 合约:

equals():

equals 方法在非空对象引用上实现等价关系:

  • 它是自反的:对于任何非空引用值 x,x.equals(x) 应该返回 true。
  • 它是对称的:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应该返回 true。
  • 它是可传递的:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true 并且 y.equals(z) 返回 true,则 x.equals(z) 应该返回 true。
  • 它是一致的:对于任何非空引用值 x 和 y,x.equals(y) 的多次调用始终返回 true 或始终返回 false,前提是没有修改对象上 equals 比较中使用的信息。
  • 对于任何非空引用值 x,x.equals(null) 应该返回 false。

hashcode():

  • 每当在 Java 应用程序执行期间对同一个对象多次调用它时,hashCode 方法必须始终返回相同的整数,前提是没有修改对象上的 equals 比较中使用的信息。该整数不需要从应用程序的一次执行到同一应用程序的另一次执行保持一致。
  • 如果两个对象根据 equals(Object) 方法相等,则对两个对象中的每一个调用 hashCode 方法必须产生相同的整数结果。
  • 如果根据 equals(java.lang.Object) 方法,如果两个对象不相等,则不需要对两个对象中的每一个调用 hashCode 方法都必须产生不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。

要记住的关键点:

  1. 如果您要覆盖 equals 方法,那么您也应该覆盖 hashcode()。
  2. 如果两个对象相等,则它们必须具有相同的哈希码。
  3. 如果两个对象具有相同的哈希码,那么它们可能相等也可能不相等
  4. 始终使用相同的属性来生成 equals 和 hashcode,就像在我们使用 name 的例子中一样。


原文链接:https://codingdict.com/