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;

/**
 * @author LISHANSHAN
 * @ClassName Employee
 * @Description TODO
 * @date 2022/04/2022/4/22 16:19
 */

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;

/**
 * @author LISHANSHAN
 * @ClassName TestEquals
 * @Description TODO
 * @date 2022/04/2022/4/22 16:24
 */

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

其余代码不变。

运行结果:

在这里插入图片描述
很显然,判重成功。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值