转:为什么在定义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 = { ...
随机推荐
- SGU 520 Fire in the Country(博弈+搜索)
Description This summer's heat wave and drought unleashed devastating wildfires all across the Earth ...
- 关于ES6-{块级作用域 let const 解构赋值 数组 字符串 函数的扩展 箭头函数}
关于ES6 块级作用域 任何一对花括号({})中的语句集都属于一个块,在块中声明的变量在代码块外都是不可访问的,称之为块级作用域,ES5以前没有块级作用域 let let 是ES6新增的声明变量的一种 ...
- Python中的eval
Python中的eval方法接受一个字符串参数,并且把字符串里面的内容当成Python代码来执行: eval的缺点是执行速度慢,并且会有安全风险
- “Hello World!”团队第三周召开的第五次会议
一.会议时间 二.会议地点 三.会议成员 四.会议内容 五.todo list 六.会议照片 七.燃尽图 八.代码地址 一.会议时间 2017年10月31日 11:45-12:17 二.会议地点: ...
- 常用排序算法--java版
package com.whw.sortPractice; import java.util.Arrays; public class Sort { /** * 遍历一个数组 * @param sor ...
- lintcode-191-乘积最大子序列
191-乘积最大子序列 找出一个序列中乘积最大的连续子序列(至少包含一个数). 样例 比如, 序列 [2,3,-2,4] 中乘积最大的子序列为 [2,3] ,其乘积为6. 标签 子数组 领英 动态规划 ...
- JDK源码分析 – LinkedList
LinkedList类的申明 public class LinkedList<E> extends AbstractSequentialList<E> implements L ...
- 【OSG】运行OSG示例出现的奶牛不完整问题
发现一个很奇怪的问题:我用笔记本运行OSG里面的示例,出现的图案总是不完整显示的,以经典的奶牛图案为例,如图. 图一是我电脑上的情况,正常情况应该是图二.不知道这是什么原因,难道是我电脑显卡的原因吗? ...
- 【Docker 命令】- ps命令
docker ps : 列出容器 语法 docker ps [OPTIONS] OPTIONS说明: -a:显示所有的容器,包括未运行的. -f:根据条件过滤显示的内容. --format :指定返回 ...
- scala中的模式匹配
基本语法 变量 match { case 值1 => 代码 case 值2 => 代码 ... case 值N if (...) => 代码 case _ => 代码 } 常量 ...