一文搞懂hashCode()和equals()

1 篇文章 0 订阅
1 篇文章 0 订阅

基本概念

hashCode()

方法作用:JDK8的原生注释如下:

  • 简单翻译就是:返回这个对象的hash code
  • 什么是hash code后文也会展开解释
 /**
 * Returns a hash code value for the object.
 */

Java基类Object的代码实现如下(是一个本地方法):

 public native int hashCode();

equals()

方法作用:JDK8的原生注释如下:

  • 简单翻译就是:表明其他对象是否“equal to”当前对象
  • 如何实现“equal to”,后文会展开解释
/**
* Indicates whether some other object is "equal to" this one.
*/

Java基类Object的代码实现如下:

public boolean equals(Object obj) {
    return (this == obj);
}

常见面试题

==和equals()有什么区别

  • ==

    • 对于基本数据类型:==就是比较值是否相等

    • 对于引用数据类型:==就是比较引用的内存地址

    • demo代码如下:

      • 虽然s1和i1的数据类型不同,但是由于值相等,所以返回true
      • integer1和integer2是两个不同的对象,引用指向的内存地址也不同,所以返回false
    public static void main(String[] args) {
        short s1 = 1;
        int i1 = 1;
        System.out.println(s1 == i1);	// 返回true
    
        Integer integer1 = new Integer(1);
        Integer integer2 = new Integer(2);
        System.out.println(integer1 == integer2);	//返回false
    
    }
    
  • equals()

    • Object的equals()方法实现等同于==.(可以参照基本概念章节中的equals()源码)
    • 实际应用中一般会重写equals()方法,用于比较对象是否相等

两个对象的 hashCode() 相同,则 equals() 也一定为 true,对吗?

我在网上看了很多帖子都说这句话是错误的,严格意义来说这个题目不够严谨,这也是我写这篇帖子的初衷.这个题目的关键在于对象是否重写hashCode()方法.

  • 对象没有重写hashCode()方法

    • Object的hashCode()方法实现是返回对象的内存地址(可以通过JVM参数-XX:hashCode指定hashCode的生成策略)
    • 返回题目,hashCode相同,也就是内存地址相同,也就是同一个对象
    • 既然是同一个对象equals()返回肯定为true
  • 对象重写hashCode()方法

    • 两个对象hashCode()相同,equals()也一定为true是错误的
    • hashCode是基于hash算法计算的,不同的对象计算的hashCode结果可能相同
    • 网上大多数帖子都是用下面例子,证明这个题目错误的
      • 这个代码的关键也是因为String重写了hashCode()方法导致的
    public static void main(String[] args) {
        String s1 = "通话";
        String s2 = "重地";
    
        System.out.println(s1.hashCode() == s2.hashCode());	//true
        System.out.println(s2.equals(s1));	//false
    }
    

两个对象equals()返回为true,那么他们的hashCode()一定相同(),对吗?

严格意义来说这句话是不对的,证明代码如下:

  • 重写了equals()方法,无论怎么比较都是返回true
    • 为了预防一些“杠精”,这个代码可以把equals修改为比较对象的name属性
  • 没有重写hashCode方法,也就是复用Object的hashCode方法
  • 这个代码的执行结果equals一定为true,但是hashCode方法不相同
public class TestUserEquals {

    private String name;

    private String age;

    public static void main(String[] args) {
        TestUserEquals u1 = new TestUserEquals("cjq", "1");
        TestUserEquals u2 = new TestUserEquals("lsy", "2");
        System.out.println(u1.equals(u2));	// true
        System.out.println(u1.hashCode() == u2.hashCode());	//false
    }

    public boolean equals(Object obj) {
        return true;
    }
}

既然这句话不对,为什么网上很多人都认为这句话是正确的呢?

  • 这源于Object的hashCode源码的注释,源码注释如下:
    • 大概意思就是:如果两个对象equals返回为true,调用hashCode方法必须产生相同的整数结果
/*<li>If two objects are equal according to the {@code equals(Object)}
*     method, then calling the {@code hashCode} method on each of
*     the two objects must produce the same integer result.
*/

为什么重写了equals()方法,就要重写hashCode()方法

  • 基于hash算法的容器增加元素的核心步骤
    在这里插入图片描述

  • 从上图可以看到基于hash算法的容器,在添加元素的时候会先比较元素的hashCode,假设现在我们有一个对象User(对象有两个属性name和age),我们重写了equals方法,认为name相同的对象equals返回就是true,但是我们没有重写hashCode方法(也就是Object的hashCode方法,返回对象的内存地址),那么就算name相同的对象的hashCode也永远不会相同,就会被重复添加进入容器.也就违背了我们按照name相同去重的初衷

  • 为什么有hashCode分组概念?为了提高性能

    • 如果目前容器已经添加了1000个元素,且没有hashCode分组概念,现在需要添加元素
    • 那么这个元素就需要和1000个元素进行equals比较,也就是循环1000次
    • 如果有了hashCode分组的概念,hash算法有比较优质,把1000个元素分成了10组,每个元素100个元素
    • 此时添加元素时,如果hash冲突也就比较100次
    • 如果没有hash冲突,直接添加进入容器

总结

  • 大家准备面试过程中不要死记硬背,抓住题目关键,讲清楚原理相信也可以打动面试官
  • 网上帖子的结论大家也要有自己的判断,最好可以动手验证
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值