`

为什么hashcode要使用31这个数

    博客分类:
  • java
阅读更多
散列计算就是计算元素应该放在数组的哪个元素里。准确的说是放到哪个链表里面。按照Java的规则,如果你要想将一个对象放入HashMap中,你的对象的类必须提供hashcode方法,返回一个整数值。比如String类就有如下方法:
public int hashCode() {  
        int h = hash;  
        int len = count;  
        if (h == 0 && len > 0) {  
            int off = offset;  
            char val[] = value;  
  
            for (int i = 0; i < len; i++) {  
                h = 31*h + val[off++];  
            }  
            hash = h;  
        }  
        return h;  
    }  


注意上面的for循环,有点搞吧?我来举个例子,让你很容易明白它在搞什么名堂。比如有一个字符串“abcde”,采用31进制的计算方法来计算这个字符串的总和,你会写出下面的计算式子:
a*31^4+b*31^3+c*31^2+d*31^1+e*31^0.注意,这里的a,b,c,d或者e指的是它们的ASCII值。很有趣的循环,居然可以用来算N进制。这个循环可以抽出来单独作为计算进制的好工具:
public static void main(String[] args) {  
        int[] a={1,0};  
        System.out.println(calculate(2,a));  
    }  
  
    private static int calculate(int radix,int[] a){  
        int sum = 0;  
        for(int i=0;i<a.length;++i){  
            sum = sum*radix+a[i];  
        }  
        return sum;  
    }  

静态方法caculate接受radix作为进制基数,数组a模拟要计算的进制的数字,只是注意表面顺序需要一致。比如 01 二进制串,在数组中要按照{0,1}排列。上面的输出结果是1,符合01的真实值。
  那么为什么选用31作为基数呢?先要明白为什么需要HashCode.每个对象根据值计算HashCode,这个code大小虽然不奢求必须唯一(因为这样通常计算会非常慢),但是要尽可能的不要重复,因此基数要尽量的大。另外,31*N可以被编译器优化为
左移5位后减1,有较高的性能。其实选用31还是有争议,反对者(参考http://stackoverflow.com/questions/299304/why-does-javas-hashcode-in-string-use-31-as-a-multiplier
认为这个东西还是会导致较多的重复,应该用更大的数字。所以,或许将来Java的实现中会有所变化。下面这篇文章介绍了两个结论:
1.基数要用质数
质数的特性(只有1和自己是因子)能够使得它和其他数相乘后得到的结果比其他方式更容易产成唯一性,也就是hash code值的冲突概率最小。
2.选择31是观测分布结果后的一个选择,不清楚原因,但的确有利。
http://computinglife.wordpress.com/2008/11/20/why-do-hash-functions-use-prime-numbers/
另外,String.hashCode内部会缓存第一次计算的值,因为这是一个final(不可变)类,也就是String对象的内容是不会变的。这能够在多次put到HashMap的场合提高性能,不过似乎用处不多。
分享到:
评论

相关推荐

    定义hashcode时使用31系数的原因

    那么,为什么使用31作为系数呢?首先,31是一个质数,它的特性是只有1和自己是因子。这使得它和其他数相乘后得到的结果比其他方式更容易产成唯一性,也就是hash code值的冲突概率最小。其次,31*N可以被编译器优化为...

    javascript中实现兼容JAVA的hashCode算法代码分享

    Java中String类的hashCode方法采用特定的算法,即:初始时,哈希码值为0,然后以字符为单位,对于字符串中的每一个字符,都使用31乘以当前哈希码,然后加上当前字符的ASCII值,然后更新哈希码。 2. **JavaScript中...

    java编程的常见规则

    12. **合理使用equals()与hashCode()**:当重写equals()时,也要重写hashCode(),保持一致性。 13. **集合初始化**:使用集合的构造函数预定义大小,避免动态扩容带来的性能损失。 14. **避免在循环中创建对象**:...

    JAVA常用类的使用方法

    如`parseInt()`用于将字符串转换为整数,`compareTo()`用于比较两个`Integer`对象的大小,`toString()`将整数转换为字符串,还有`byteValue()`、`doubleValue()`、`floatValue()`、`hashCode()`、`intValue()`等。...

    Microsoft.Net常见问题集锦

    为什么要有GC?** - GC(垃圾回收机制)是一种自动管理内存的技术,它负责自动释放不再使用的对象所占用的内存空间。在 .Net 平台上,GC 的存在极大地简化了程序员的工作,避免了手动释放内存导致的内存泄漏等问题...

    疯狂JAVA讲义

    学生提问:为什么要用this来调用另一个重载的构造器?我把另一个构造器里的代码复制、粘贴到这个构造器里不就可以了吗? 143 5.6 类的继承 144 5.6.1 继承的特点 144 5.6.2 重写父类的方法 145 5.6.3 父类实例的...

    Java集合框架,来自个人参考其他资源学习的笔记1

    System.out.println("集合中的元素个数为:" + nameSet.size()); // 输出 3 } } ``` ##### 2.2 HashSet类的无重复特性 - **哈希码(Hashcode)的作用**:`HashSet`利用哈希码(`hashcode`)来判断元素是否重复...

    Java面试题.txt

    ### Java面试题精析 #### 1. final, finally, finalize 的区别 - **final**:此关键字在Java中...在这个例子中,Singleton类使用了饿汉式实现,实例在类加载时就已创建,保证了线程安全,但可能在未使用时占用内存。

    写给大忙人看的JAVA SE 8

    1.1 为什么要使用lambda表达式 2 1.2 lambda表达式的语法 4 1.3 函数式接口 6 1.4 方法引用 8 1.5 构造器引用 10 1.6 变量作用域 10 1.7 默认方法 14 1.8 接口中的静态方法 17 练习 18 第2章 Stream API 20 2.1 从...

    Java面试测试题目2018张大成总结

    为什么Java里没有全局变量 - Java中使用静态变量来模拟全局变量的行为,避免全局变量可能导致的问题。 #### 57. 如何将String类型转化成Number类型 - 使用`Integer.parseInt()`、`Double.parseDouble()`等方法。

    哈希码

    4. **确保结果在整数范围内**:`hashCode()`方法应该返回一个`int`类型的值,范围为`-2^31`到`2^31-1`。 总之,哈希码是Java中提高数据处理效率的重要工具,它使得我们能够在大型数据集上执行快速查找和操作。理解...

    活用JAVA语言JDK已有的类

    在这个简单的Java数学计算小程序中,我们可以利用JDK内置的日期处理类`java.util.Date`以及整数处理类`java.lang.Integer`来实现功能。下面将详细介绍这两个类的一些主要方法。 首先,我们来看`java.util.Date`类,...

    Java面试八股文十万字总结.docx

    有数组了为什么还要搞个ArrayList呢?** - 提供了更多便捷的操作方法。 - 可以自动扩展大小。 - 支持更多的集合操作。 **38. 说说什么是fail-fast?** 当多个线程同时访问一个集合时,如果一个线程修改了集合,...

    java基础知识点67条

    - 每当使用`new`关键字创建一个对象时,都会在堆内存中为该对象分配空间,这是Java内存管理的基础。 #### 39. hashCode概念 - `hashCode`相当于对象的身份证号码,用于快速比较对象的相等性。虽然它不是唯一的,但...

    java面试题总结

    为什么要有GC? - **GC**:Garbage Collection,自动回收不再使用的对象。 - **目的**:避免内存泄漏,提高程序效率。 #### 26. Strings=newString("xyz");创建了几个String Object? - **创建**:创建了一个`...

    Java开发实战1200例(第1卷).(清华出版.李钟尉.陈丹丹).part3

    全书压缩打包成4部分,这是第3部分 注:本系列图书的第I、II卷再版时均相应改名为《xxx开发实例大全》(基础卷)及(提高卷),但内容基本无变化,需要的童鞋可自由匹配查找。 内容简介  《Java开发实战1200例》分为I...

    Java入门1·2·3:一个老鸟的Java学习心得.PART3(共3个)

    为什么要重载? 168 7.5.3 给汽车加个重载的方法 169 7.5.4 测试一下 169 7.5.5 重载容易引发误解的两个地方——返回类型和形参名 170 7.5.6 重载中的最难点——参数匹配原则 171 7.6 使用类的实例作为方法参数...

Global site tag (gtag.js) - Google Analytics