栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

equals方法和hashCode()方法

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

equals方法和hashCode()方法

1. hashCode()简介

该方法主要是利用一定的规则生成对象的哈希码,也称散列码。它是是由对象导出的一个整数值,是没有规律的。

关于hashCode()使用的哈希算法,越糟糕的哈希算法越容易产生哈希碰撞(产生重复的哈希码),不过这也与数据值域分布特性有关。

2. hashCode()的作用

在将对象插入类似于HashSet等集合中时,

  1. 首先计算对象的hashCode,来判断对象加入的位置,同时也会与其他已经加入的对象的hashCode值作比较。
  2. 如果没有相等的hashCode,HashSet会假设对象没有重复出现,直接将其加入;
  3. 但是如果发现有重复的hashCode值的对象,会调用equals方法来检查hashCode值相等的对象是否真的相同。
  4. 如果不同,就会重新散列到不同的位置;如果相等,则不进行插入。
3. 既生equals,何生hashCode

可以看出hashCode和equals方法,本质都是用来比较对象是否相等的。

为什么JDK要同时提供两个方法呢?

如上所述,在一些容器,比如HashSet、HashMap中,hashCode方法的存在是非常有必要的,它可以减少使用equals比较的次数。
毕竟,在较少数据的情况下,使用equals进行比较,结果会很准确,也很方便。
但是,如果数据数量很大呢?此时使用equals一条一条按照规则比较两个对象是否相等的复杂度,是不可估量的。而这正是hashCode的用途所在,它产生的哈希码是个整型数据,比较起来相对于对象更加简单。很显然,有hashCode大大提高了比较的效率。

为什么重写了equals后,就也要重写hashCode呢?

在实际应用中,都是按照一定规则来判断对象是否相等的,比如说工号相等的两个员工,可以认为是同一个人。这时,为了使程序判定二者相等,势必要重写equals。
那么,hashCode呢?

不重写时

比较时,使用的是Object中的hashCode方法。
结果大概率会是,重写后的equals判断相等的两个对象,原始的hashCode方法获取的哈希码是不相等的。

情况一

当然,如果不将对象放入散列表中,其实问题不大,因为直接equals比较两个对象就可以了,hashCode比较的结果,根本无所谓啦。

情况二

那么当想要将两个对象插入进HashSet呢?
问题来啦!
首先调用hashCode判断,二者不相等,那么,插入成功。也就是说,此时,员工表中存在两个工号相同的员工。
那就现实意义而言,一张员工表中,可以存在两个工号相同的员工嘛?很显然,不能。因为这在现实中,就是员工信息出现重复了。

这也就是重写equal后,要重写hashCode的原因。
文字叙述不够直观,直接来栗子吧。

4. 栗子1:

重写了equals(),没有重写hashCode()。

注意啊,这里的重写,是要加@Override的。不然,Objects可是不承认的。

1. 员工类
package test;



public class Employee {
    private String employeeId;
    private String employeeName;
    private double salary;

    public Employee(String employeeId, String employeeName, double salary) {
        this.employeeId = employeeId;
        this.employeeName = employeeName;
        this.salary = salary;
    }

    @Override
    public boolean equals(Object o) {
        Employee employee = (Employee) o;
        if (employeeId.equals(employee.getEmployeeId())) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public String toString() {
        return "Employee{" +
                "employeeId='" + employeeId + ''' +
                ", employeeName='" + employeeName + ''' +
                ", salary=" + salary +
                '}';
    }

    public String getEmployeeId() {
        return employeeId;
    }

    public void setEmployeeId(String employeeId) {
        this.employeeId = employeeId;
    }

    public String getEmployeeName() {
        return employeeName;
    }

    public void setEmployeeName(String employeeName) {
        this.employeeName = employeeName;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }
}

2. 测试方法
package test;

import java.util.HashSet;
import java.util.Set;



public class TestEquals {

    public static void main(String[] args) {
        Employee e1 = new Employee("001", "张三", 10000);
        Employee e2 = new Employee("001", "张三", 10000);

        System.out.println("e1的hashcode: " + e1.hashCode());
        System.out.println("e2的hashcode: " + e2.hashCode());
        System.out.println("e1和e2相等? " + e1.equals(e2));
        System.out.println("e1和e2的哈希码相等?" + (e1.hashCode() == e2.hashCode()));

        HashSet set = new HashSet<>();
        set.add(e1);
        set.add(e2);
        System.out.println(set.size());
        set.forEach((employee)-> System.out.println(employee));
    }
}
3. 运行结果

5. 栗子2: 如何重写

简单介绍两种重写的方式吧。

  1. 最好使用null安全的Objects.hashCode()。如果其参数为null,会返回0,否则返回对参数调用hashCode方法的结果。
    另外,对double类型的对象,调用静态方法Double.hashCode方法来避免创建Double对象。系数是随便取的。
  2. 需要组合多个散列值时,可以调用Objects.hash并提供多个参数,会对各个参数调用Objects.hashCode,并组合这些散列值。
@Override
public int hashCode() {
	return 7 * Objects.hashCode(employeeId)
	 + 11 * Double.hashCode(salary) 
	 + 13 * Objects.hashCode(employeeName);
}

@Override
public int hashCode() {
	return Objects.hash(name, salary, hireDay);
}

增加一个hashCode()

还是上述例子,Employee类中新增一个hashCode方法,如下:

@Override
    public int hashCode() {
        return Objects.hash(employeeId, employeeName, salary);
    }

其余代码不变。

运行结果:


很显然,判重成功。

以上纯属个人看法,如有不同意见,请与我交流呀。

都看到这里了,真的不点个赞嘛?(☆▽☆)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/832053.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号