Java hashCode()方法

写在前边
  • 现在的时间:2019-06-05
  • 一共讨论两个问题:hashCode()方法与euqals()方法的关系、hashCode()方法在HashMap等散列的数据结构中有什么作用
  • 没有高深的理论,以简单理解为主.

hashCode()方法与 euqals()方法的关系
euqals()方法讲解
  • 第一次学Java的时候,有一个重点你肯定知道:比较两个字符串的内容是否相等要用euqals()方法,不能用==.
  • 所以我们可以这样理解:euqals()方法是用来比较两个对象中的内容是否相同的,相同会返回true,不相同返回flase.
  • 那对象中的内容指的是什么呢,其实就是对象中的属性,对String来说就是字符串的内容了.
  • 但如果我们自己定义一个类然后创建两对象,用equals()方法比较这两个属性值一样的对象,结果却会返回false.
  • 为什么会这样呢,当对象p1调用euqals()方法时,因为它所属的类中并没有重写这个方法,所以会去调用父类中的euqals()方法,也就是Object中的equals()方法,其源码如下
    public boolean equals(Object obj)
    {
            return (this == obj);
    }
    
    从源码中可以看出,只有两个对象是同一个对象时,才会返回true,但我们要求只要两个对象的所有属性值相同即返回true.
  • 为了达到只要两个对象的所有属性值相同即返回true的要求,我们要在People类中重写Object中的equals()方法.
  • 那么,为什么String的对象(字符串)调用equals()方法就是比较两个字符串的内容是否相同而不是Object中equals()方法写的比较是否是同一个对象呢,这是因为String类已经重写了equals()方法,其源码如下:
    public boolean equals(Object anObject) 
    {
        if (this == anObject) 
        {
            return true;
        }
        if (anObject instanceof String) 
        {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) 
            {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) 
                {
                    if (v1[i] != v2[i])
                    {
                        return false;
                    }
                    i++;
                }
                return true;
            }
        }
        return false;
    }
    
hashCode()方法与euqals()方法的关系
  • hashCode()方法会返回一个int值,这个int值就是这个对象对应的哈希值.
  • 这个方法也存在于Object中,其源代码是public native int hashCode();
  • 就现在所讲的而言,可以这样理解hashCode()的作用:这个方法会返回调用它的对象的哈希值,这样就把哈希值与这个对象对应起来了,一个哈希值可能对应着多个对象,但一个对象只对应一个哈希值.
  • hashCode()euqals()有以下关系:
    • 如果equals()为true,说明是同一个对象,那么两个对象的hashCode()一定相同.
    • 如果equals()为false,说明不是同一个对象,那么两个对象的hashCode()可能相同也可能不同.
    • 如果两个对象hashCode()相同,则一定是同一个对象,equals()为true.
    • 如果两个对象hashCode()不同,则可能是同一个对象也可能不是同一个对象,equals()可能为true,也可能为false.
  • 可以看到当equals()方法为true时,两个对对象调用hashCode()的值一定相同,所以我们有以下结论:如一个类重写了equals()方法,那么它必须也重写hashCode()方法,否则就会出现equals()为true但hashCode()不同的情况.

hashCode()方法在HashMap等散列的数据结构中的作用
HashMap简单回顾
  • HashMap中的数据是以K-V的形式存在的.
  • 数据是无序不可重复的,不可重复指的是K-VK不可重复.
  • 如果存入有相同KK-V数据,那么这条数据的V会覆盖原来数据的V.
如何保证不可重复

下边是最通俗的方法,但在Java中并不使用这种方法,这只是为了引出hashCode()的使用而意想出来的.

  • 假设现在HashMap中已经有了100条K-V数据.
  • 现在要存入一条新的K-V,那么就拿要存入数据的K和每一条数据的K比较,如果遇到相同的就覆盖数据,假如全都不相同,那么存入这条K-V.
    • 也就是说用equals()方法比较新的K与已存在的K,相同则V覆盖上去,全不相同则K-V存入.
  • 可见如果要存入这条数据最坏的情况要比较100次,最好的情况要比较1次.
    • K-V只存入了V即要存入的数据覆盖了原来的数据,我们称为存入了数据
    • K-V原先K就不存在KV都存入了,我们也称为存入了数据
使用hashCode()保证不可重复

这是Java使用的方法

  • 还是假设HashMap中已经有了100条K-V数据.
  • 假设这100个K是:K1,K2,K3,...,K100
  • HashMap会用每个K调用hashCode()方法,计算出每个K的哈希值,前边我们说过一个哈希值可能对应着多个对象,但一个对象只对应一个哈希值,所以最后可以形成这样一个表.
哈希值哈希值对应的K
9527K1,K34,K22,…
7855K3,K5,K99,…
7865K9,K77,K49,…
  • 当我们再要存入一条新的K-V时,HashMap会调用hashCode()计算出新的K-V的K对应的哈希值,然后与表中的哈希值比较.
    • 如果有相同的哈希值,那么需要再调用equals()方法比较这个新的K这个哈希值对应的所有K,因为hashCode()相同,equals()不一定为false也不一定为true,如果结果为true说明原先有个K和新的K相同,新的V覆盖原来的V;如果结果全部为false,则将K-V存入.
    • 如果没有相同的哈希值,则直接存入新的K-V,因为hashCode()不同则equals()一定为false,则新的K一定不存在.
  • 可见,要存入数据最好的情况需要比较2次,最坏的情况需要比较 f ( a , b ) m a x f(a,b)_{max} f(a,b)max
    • f ( a , b ) = a + b a ∈ [ 1 , 那 个 表 格 的 行 数 ] b ∈ [ 1 , K 值 最 多 的 那 一 行 K 的 个 数 ] f(a,b)=a+b \\ a\in[1,那个表格的行数] \\b\in[1,K值最多的那一行K的个数] f(a,b)=a+ba[1,]b[1,KK]
    • 最坏的情况需要比较的次数虽然没办法准确确定,但显示小于原先的100次.
  • 如此,使用hashCode(),在存入新的数据时便大大减少了用equals()比较的次数,提高了效率,这便是hashCode()在HashMap等散列的数据结构中的作用.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值