zoukankan      html  css  js  c++  java
  • 【Java概念每日一题004】两个对象hashCode()相同,则equals()也一定为true?

    原文链接:https://www.cnblogs.com/Qian123/p/5703507.html#_label1

    hashcode() 方法详解

    hashCode()方法给对象返回一个hash code值。这个方法被用于hash tables,例如HashMap。

    它的性质是:

    • 在一个Java应用的执行期间,如果一个对象提供给equals做比较的信息没有被修改的话,该对象多次调用hashCode()方法,该方法必须始终如一返回同一个integer。

    • 如果两个对象根据equals(Object)方法是相等的,那么调用二者各自的hashCode()方法必须产生同一个integer结果。

    • 并不要求根据equals(java.lang.Object)方法不相等的两个对象,调用二者各自的hashCode()方法必须产生不同的integer结果。然而,程序员应该意识到对于不同的对象产生不同的integer结果,有可能会提高hash table的性能。

    大量的实践表明,由Object类定义的hashCode()方法对于不同的对象返回不同的integer。

    在object类中,hashCode定义如下:

    public native int hashCode();

    说明是一个本地方法,它的实现是根据本地机器相关的。当然我们可以在自己写的类中覆盖hashcode()方法,比如String、Integer、Double等这些类都是覆盖了hashcode()方法的。例如在String类中定义的hashcode()方法如下:

    public int hashCode() {  
        int h = hash;  
        if (h == 0) {  
            int off = offset;  
            char val[] = value;  
            int len = count;  
      
            for (int i = 0; i < len; i++) {  
                h = 31 * h + val[off++];  
            }  
            hash = h;  
        }  
        return h;  
    }

    (String的API中写到):s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1]

    使用 int 算法,这里 s[i] 是字符串的第 i 个字符,n 是字符串的长度,^ 表示求幂(空字符串的哈希码为 0)。

    想要弄明白hashCode的作用,必须要先知道Java中的集合。  
           总的来说,Java中的集合(Collection)有两类,一类是List,再有一类是Set。前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。这里就引出一个问题:要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢?
            这就是Object.equals方法了。但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。也就是说,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它就要调用1000次equals方法。这显然会大大降低效率。   
           于是,Java采用了哈希表的原理。哈希(Hash)实际上是个人名,由于他提出一哈希算法的概念,所以就以他的名字命名了。哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上,初学者可以简单理解,hashCode方法实际上返回的就是对象存储的物理地址(实际可能并不是)。  
           这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。所以这里存在一个冲突解决的问题。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。  

    简而言之,在集合查找时,hashcode能大大降低对象比较次数,提高查找效率!

    Java对象的eqauls方法和hashCode方法是这样规定的:

    1、相等(相同)的对象必须具有相等的哈希码(或者散列码)。

    2、如果两个对象的hashCode相同,它们并不一定相同。

    以下是Object对象API关于equal方法和hashCode方法的说明:

    • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
    • It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.
    • 以上API说明是对之前2点的官方详细说明

    关于第一点,相等(相同)的对象必须具有相等的哈希码(或者散列码),为什么?

    想象一下,假如两个Java对象A和B,A和B相等(eqauls结果为true),但A和B的哈希码不同,则A和B存入HashMap时的哈希码计算得到的HashMap内部数组位置索引可能不同,那么A和B很有可能允许同时存入HashMap,显然相等/相同的元素是不允许同时存入HashMap,HashMap不允许存放重复元素。

    关于第二点,两个对象的hashCode相同,它们并不一定相同

    也就是说,不同对象的hashCode可能相同;假如两个Java对象A和B,A和B不相等(eqauls结果为false),但A和B的哈希码相等,将A和B都存入HashMap时会发生哈希冲突,也就是A和B存放在HashMap内部数组的位置索引相同这时HashMap会在该位置建立一个链接表,将A和B串起来放在该位置,显然,该情况不违反HashMap的使用原则,是允许的。当然,哈希冲突越少越好,尽量采用好的哈希算法以避免哈希冲突。

     所以,Java对于eqauls方法和hashCode方法是这样规定的:

    1.如果两个对象相同,那么它们的hashCode值一定要相同;

    2.如果两个对象的hashCode相同,它们并不一定相同(这里说的对象相同指的是用eqauls方法比较)。  

    如不按要求去做了,会发现相同的对象可以出现在Set集合中,同时,增加新元素的效率会大大下降。

    3.equals()相等的两个对象,hashcode()一定相等;equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。

            换句话说,equals()方法不相等的两个对象,hashcode()有可能相等(我的理解是由于哈希码在生成的时候产生冲突造成的)。反过来,hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。

    在object类中,hashcode()方法是本地方法,返回的是对象的地址值,而object类中的equals()方法比较的也是两个对象的地址值,如果equals()相等,说明两个对象地址值也相等,当然hashcode()也就相等了;在String类中,equals()返回的是两个对象内容的比较,当两个对象内容相等时,Hashcode()方法根据String类的重写代码的分析,也可知道hashcode()返回结果也会相等。以此类推,可以知道Integer、Double等封装类中经过重写的equals()和hashcode()方法也同样适合于这个原则。当然没有经过重写的类,在继承了object类的equals()和hashcode()方法后,也会遵守这个原则。

         

  • 相关阅读:
    Struts2拦截器
    Struts2 数据封装与值栈
    Struts2的环境搭配
    自学spring AOP
    小白学Maven第二篇配置Ecilpse
    小白学Maven第一篇配置
    web项目jsp出现The superclass javax.servlet.http.HttpServlet was not found on the Java Build Path错误
    软件测试复习(二)
    软件测试复习(一)
    白盒测试概述
  • 原文地址:https://www.cnblogs.com/Neil-J/p/13547244.html
Copyright © 2011-2022 走看看