最近我读了这篇文章 开发人员工作文件。

该文档是关于有效和正确地定义hashCode()和equals(),但我无法弄清楚为什么我们需要覆盖这两个方法。

我如何决定有效地实现这些方法?


当前回答

hashCode ():

如果只重写hash-code方法,什么也不会发生,因为它总是为每个对象返回一个新的hashCode作为object类。

equals ():

如果你只覆盖equals方法,如果a.equals(b)为真,这意味着a和b的hashCode必须是相同的,但这不会发生,因为你没有覆盖hashCode方法。

注意:Object类的hashCode()方法总是为每个对象返回一个新的hashCode。

因此,当您需要在基于哈希的集合中使用对象时,必须重写equals()和hashCode()。

其他回答

hashCode()方法用于获取给定对象的唯一整数。这个整数用于确定桶的位置,当这个对象需要存储在一些HashTable, HashMap之类的数据结构时。默认情况下,Object的hashCode()方法返回存储Object的内存地址的整数表示形式。

对象的hashCode()方法用于将对象插入到HashTable、HashMap或HashSet中。更多关于哈希表的信息请参见Wikipedia.org。

要在map数据结构中插入任何条目,我们需要键和值。如果键和值都是用户定义的数据类型,则键的hashCode()将确定在内部将对象存储在何处。当还需要从映射中查找对象时,键的哈希码将确定在哪里搜索对象。

哈希码只在内部指向某个“区域”(或列表,桶等)。因为不同的键对象可能具有相同的哈希码,所以哈希码本身并不能保证找到正确的键。然后哈希表迭代该区域(具有相同哈希代码的所有键),并使用键的equals()方法找到正确的键。一旦找到正确的键,就会返回为该键存储的对象。

因此,正如我们所看到的,hashCode()和equals()方法的组合在哈希表中存储和查找对象时使用。

注:

总是使用对象的相同属性来生成hashCode()和equals()。在我们的例子中,我们使用了员工id。 Equals()必须是一致的(如果对象没有被修改,那么它必须一直返回相同的值)。 当a. = (b)时,则a.hashCode()必须与b. hashcode()相同。 如果你覆盖了一个,那么你也应该覆盖另一个。

http://parameshk.blogspot.in/2014/10/examples-of-comparable-comporator.html

让我用非常简单的话来解释这个概念。

首先,从更广泛的角度来看,我们有集合,而hashmap是集合中的数据结构之一。

要理解为什么我们必须重写equals和hashcode方法,如果需要的话,首先要理解什么是hashmap以及它的功能。

hashmap是一种以数组方式存储键值对数据的数据结构。假设是a[],其中'a'中的每个元素都是一个键值对。

此外,上述数组中的每个索引都可以是链表,因此在一个索引上有多个值。

为什么要使用hashmap呢?

如果我们必须在一个大数组中搜索,那么搜索每个数组,如果它们不是有效的,那么哈希技术告诉我们,让我们用一些逻辑预处理数组,并根据该逻辑对元素进行分组,即哈希

例如:我们有数组1、2、3、4、5、6、7、8、9、10、11,我们应用哈希函数mod 10,所以1、11将被分组在一起。因此,如果我们必须在前一个数组中搜索11,那么我们必须迭代整个数组,但当我们对它进行分组时,我们限制了迭代的范围,从而提高了速度。为了简单起见,用于存储所有上述信息的数据结构可以看作是一个2d数组

现在除了上面的hashmap还告诉它不会在其中添加任何duplicate。这就是为什么我们要重写等号和hashcode的主要原因

因此,当我们说要解释hashmap的内部工作时,我们需要找到hashmap有什么方法,以及它如何遵循上面我解释过的规则

所以hashmap有一个方法叫as put(K,V),根据hashmap,它应该遵循上面的规则,有效地分配数组,不添加任何重复

put所做的是首先为给定的键生成hashcode来决定值应该放在哪个索引中。如果那个下标处什么都没有,那么新值就会被加到那里,如果那里已经有了,那么新值就会被加到链表末尾那个下标处。但是请记住,不应该根据期望的hashmap行为添加重复项。假设你有两个整数对象aa=11 bb=11。

由于每个对象都派生自对象类,比较两个对象的默认实现是比较引用,而不是对象内部的值。因此,在上述情况下,尽管语义上相同,但两个对象都将无法通过相等性测试,并且有可能存在两个具有相同hashcode和相同值的对象,从而创建重复的对象。如果我们重写,就可以避免添加重复项。 您也可以参考详细工作

import java.util.HashMap;


public class Employee {
    String name;
    String mobile;

    public Employee(String name,String mobile) {
        this.name = name;
        this.mobile = mobile;
    }
    
    @Override
    public int hashCode() {
        System.out.println("calling hascode method of Employee");
        String str = this.name;
        int sum = 0;
        for (int i = 0; i < str.length(); i++) {
            sum = sum + str.charAt(i);
        }
        return sum;
    }

    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        System.out.println("calling equals method of Employee");
        Employee emp = (Employee) obj;
        if (this.mobile.equalsIgnoreCase(emp.mobile)) {
            System.out.println("returning true");
            return true;
        } else {
            System.out.println("returning false");
            return false;
        }
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Employee emp = new Employee("abc", "hhh");
        Employee emp2 = new Employee("abc", "hhh");
        HashMap<Employee, Employee> h = new HashMap<>();
        //for (int i = 0; i < 5; i++) {
            h.put(emp, emp);
            h.put(emp2, emp2);
        //}
        
        System.out.println("----------------");
        System.out.println("size of hashmap: "+h.size());
    }
}
public class Employee {

    private int empId;
    private String empName;

    public Employee(int empId, String empName) {
        super();
        this.empId = empId;
        this.empName = empName;
    }

    public int getEmpId() {
        return empId;
    }

    public void setEmpId(int empId) {
        this.empId = empId;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    @Override
    public String toString() {
        return "Employee [empId=" + empId + ", empName=" + empName + "]";
    }

    @Override
    public int hashCode() {
        return empId + empName.hashCode();
    }

    @Override
    public boolean equals(Object obj) {

        if (this == obj) {
            return true;
        }
        if (!(this instanceof Employee)) {
            return false;
        }
        Employee emp = (Employee) obj;
        return this.getEmpId() == emp.getEmpId() && this.getEmpName().equals(emp.getEmpName());
    }

}

测试类

public class Test {

    public static void main(String[] args) {
        Employee emp1 = new Employee(101,"Manash");
        Employee emp2 = new Employee(101,"Manash");
        Employee emp3 = new Employee(103,"Ranjan");
        System.out.println(emp1.hashCode());
        System.out.println(emp2.hashCode());
        System.out.println(emp1.equals(emp2));
        System.out.println(emp1.equals(emp3));
    }

}

在对象类中,equals(Object obj)用于比较地址比较,这就是为什么在Test类中,如果你比较两个对象,则equals method给出false,但当我们重写hashcode()时,它可以比较内容并给出正确的结果。

我正在研究解释“如果你只覆盖hashCode,那么当你调用myMap.put(first,someValue)时,它首先接受,计算它的hashCode并将其存储在给定的桶中。然后,当你调用myMap.put(first,someOtherValue)时,它应该根据Map文档将first替换为second,因为它们是相等的(根据我们的定义)。”:

我认为第二次添加myMap时应该是第二个对象比如myMap。put(second,someOtherValue)

为了在HashMap, Hashtable等集合中使用我们自己的类对象作为键。,我们应该通过了解集合的内部工作来重写这两个方法(hashCode()和equals())。否则,它会导致我们意想不到的错误结果。