Java 深入理解hashcode()方法——Boolean

时间:2021-12-27 16:20:23

Java 深入理解hashcode()方法——Boolean

环境:jdk1.8


    public static void main(String []args)
    {
        Boolean b2=true;
        Boolean b3=false;

        System.out.println("ture的hash值:"+b2.hashCode());
        System.out.println("false的hash值:"+b3.hashCode());
    }

输出结果:
ture的hash值:1231
false的hash值:1237

为什么会返回1231与1237这两个诡异的数字呢(虽然hashcode值一直都很诡异@_@)?

让我们打开Boolean的源码

/** * Returns a hash code for a {@code boolean} value; compatible with * {@code Boolean.hashCode()}. * * @param value the value to hash * @return a hash code value for a {@code boolean} value. * @since 1.8 */
    public static int hashCode(boolean value) {
        return value ? 1231 : 1237;

   }

为什么是1231和1237,而不是我们经常用的1和0?

然后查阅了资料,发现有一种解释如下:


不管使用什么哈希算法,其哈希函数都要极可能避免冲突。简单地说,不同的值要落在不同的存贮单元。认真观察,很容易发现1231和1237都是素数。使用素数的好处在于,对于不同数目的存贮单元m,1231和1237基本上都与其互质,除非m等于或数倍于1231和1237。这种情况下,true和false也能落到不同的单元去。


其实这也就是一般hash算法取值的默认规则,取素数。

一般来说,单个Boolean类型是没有求hashcode的需求的。
比如这样:

  public static void main(String []args)
    {
        HashMap<Boolean,String> map=new HashMap<Boolean, String>();
        map.put(true,"这是true");
        map.put(false,"这是false");
    }

此时的Boolean的hashcode规则怎么去取都是无所谓的,取0,1可以,取1231,1237也可以,因为key有且最多只有2种可能,所以必然不可能发生碰撞。

但是,Boolean的hashcode一般是作为整体的一部分而存在的,此时就需要考虑碰撞冲突问题了。
比如下列代码

class hashTest
{
    Boolean a;
    Boolean b;
    Boolean c;
    Boolean d;

    /** * 重写hashcode * @return */
    @Override
    public int hashCode()
    {
        int hashResult=0;
        hashResult = 31 * hashResult + a.hashCode();
        hashResult = 31 * hashResult + b.hashCode();
        hashResult = 31 * hashResult + c.hashCode();
        hashResult = 31 * hashResult + d.hashCode();
        return hashResult;
    }
}

很显然,当Boolean的hashcode默认取0,1时。。。。麻烦就大了,几乎每次都会发生碰撞。
而取1231,1237,对于不同数目的存贮单元m,1231和1237基本上都与其互质,除非m等于或数倍于1231和1237。所以发生碰撞的概率大大减小。

所以,Boolean的hashcode()采用了1231,1237两个素数,而不是其他,比如0,1.
而至于为啥不是其他素数,那估计Java源代码作者比较喜欢1231,1237,想留个彩蛋?