转:为什么在定义hashcode时要使用31这个数呢?
散列计算就是计算元素应该放在数组的哪个元素里。准确的说是放到哪个链表里面。按照Java的规则,如果你要想将一个对象放入HashMap中,你的对象的类必须提供hashcode方法,返回一个整数值。比如String类就有如下方法:
- publicint int int if && len > ) {
- int char forint; i < len; i++) {
- *h + val[off++];
- return }
注意上面的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进制。这个循环可以抽出来单独作为计算进制的好工具:
- publicstaticvoid
int,}; - ,a));
- privatestaticintintint
int; - forint;i<a.length;++i){
- return
}
静态方法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这个数呢?的更多相关文章
- 为什么在定义hashcode时要使用31这个数呢?
散列计算就是计算元素应该放在数组的哪个元素里.准确的说是放到哪个链表里面.按照Java的规则,如果你要想将一个对象放入HashMap中,你的对象的类必须提供hashcode方法,返回一个整数值. ht ...
- 在php中定义常量时,const与define的区别?
问]在php中定义常量时,const与define的区别? [答]使用const使得代码简单易读,const本身就是一个语言结构,而define是一个函数.另外const在编译时要比define快很 ...
- PHP 中 define() 和 const 定义常量时的区别
自 PHP 5.3.0 起,有两种方式定义常量,使用 const 关键字或者 define() 函数: 1 2 const FOO = 'BAR'; define('FOO', 'BAR'); 这 ...
- JavaScript 中定义变量时有无var声明的区别
关于JavaScript中定义变量时有无var声明的区别 var a=5; //正确 a=5; //正确 在javascript中,以上两种方法都是定义变量的正确方法.微软的Script56.CHM中 ...
- python定义函数时的默认返回值
python定义函数时,一般都会有指定返回值,如果没有显式指定返回值,那么python就会默认返回值为None, 即隐式返回语句: return None 执行如下代码 def now(): prin ...
- python定义函数时默认参数注意事项
如果在调用一个函数时,没有传递默认参数,则函数内的默认参数是对函数的默认参数属性__defaults__的引用, 如 def func(arg1=[]): arg1.append(2) 调用func时 ...
- PHP定义字符串时单引号和双引号的区别
一般用单引号或双引号标识一个字符串.单引号串与双引号串,在PHP中的处理是不同的.双引号中的内容可以被解释并被替换,单引号串中的内容则被作为普通字符处理. 例如: $str=6; echo " ...
- python定义函数时的参数&调用函数时的传参
一.定义函数: 1.位置参数:直接定义参数 2.默认参数(或者关键字参数):参数名 = "默认值" 3.位置参数必须在默认参数之前 二.调用函数: 1.按位置传,直接写参数的值 2 ...
- 【转载】最近在用Arrays的asList()生成的List时,List元素的个数时而不正确,数组转化为List,即Arrays.asList(intArray);
最近在用Arrays的asList()生成的List时,List元素的个数时而不正确. Java代码 //经多次测试,只要传递的基本类型的数组,生成List的元素个数均为1 char arrc = { ...
随机推荐
- 阿里云搭建bind服务,外网ip不能用来解析问题解决
options { listen-on port 53 { any; }; //端口开放any listen-on-v6 port 53 { ::1; }; directory "/var/ ...
- 定点数(fixed-point number)
定义 定点数(fixed-point number)就是小数点位置固定的数,也就是说,小数点后面的位数是固定的,比如要记录一笔账目,这些账目的数字都不会超过100,就可以使用2位小数位定点数来记录,比 ...
- “小葵日记”API接口文档
"小葵日记"项目API接口文档 时间:2017/10/31 (1)用户登录[待完成] POST:127.0.0.1/index/user/login data 数据别称 数据名 数 ...
- ACM 第九天
动态规划1 动态规划问题是面试题中的热门话题,如果要求一个问题的最优解(通常是最大值或者最小值),而且该问题能够分解成若干个子问题,并且小问题之间也存在重叠的子问题,则考虑采用动态规划. 1.LLS ...
- LintCode-66.二叉树的前序遍历
二叉树的前序遍历 给出一棵二叉树,返回其节点值的前序遍历. 样例 给出一棵二叉树 {1,#,2,3}, 返回 [1,2,3]. 挑战 你能使用非递归实现么? 标签 递归 二叉树 二叉树遍历 非递归 c ...
- Python 元组 集合
1. 元组 >>> a = (1,2,3,4,5) >>> b = list(a) #转换成列表对象, 可以更改 >>> b [1, 2, 3, ...
- 【OSG】运行OSG示例出现的奶牛不完整问题
发现一个很奇怪的问题:我用笔记本运行OSG里面的示例,出现的图案总是不完整显示的,以经典的奶牛图案为例,如图. 图一是我电脑上的情况,正常情况应该是图二.不知道这是什么原因,难道是我电脑显卡的原因吗? ...
- 通过access_token openid获取微信用户昵称等信息
<?php header('Access-Control-Allow-Origin:*'); $access_token = !empty($_GET['access_token'])?$_GE ...
- vim map nmap(转)
转自:http://blog.csdn.net/taoshengyang/article/details/6319106 有五种映射存在 - 用于普通模式: 输入命令时. - 用于可视模式: 可视 ...
- shell练习题讲解
写一个脚本,计算100以内所有的奇数的和以及所有偶数的和,分别显示出来#! /bin/bashsum1=0for i in `seq 1 2 100`do sum1=$[$sum1+$i]doneec ...