理解 java 中的 hashcode() 和 equals() 方法。


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

  • hashcode()
  • equals()

hashcode() 和 equals() 方法

hashcode()

您可能知道如果将条目放入 HashMap,将计算第一个哈希码,并且此哈希码用于查找此条目将存储在hashMap 中的存储桶(索引)。

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

现在这是因为如果两个国家具有相同的名称,overriden equals 方法返回 true。 这里要记住的一件事是,equals 方法的签名应该与上面相同。 让我们把这个 Country 对象放在 hashmap 中: 这里我们将在 HashMap 中使用 Country 类对象作为键,其大写名称(字符串)作为值。

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 方法在非空对象引用上实现等价关系:

  • It is reflexive::对于任何非空引用值 x,x.equals(x) 应该返回 true。
  • It is symmetric:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
  • It is transitive:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true 并且 y.equals(z) 返回 true,那么 x.equals(z) 应该返回 true。
  • It is consistent:对于任何非空引用值 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 方法必须产生不同的整数结果。但是,程序员应该意识到为不相等的对象生成不同的整数结果可能会提高哈希表的性能。 要记住的要点:

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


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