Java HashMap分析之二:Hash code

开发 后端
散列计算就是计算元素应该放在数组的哪个元素里。准确的说是放到哪个链表里面。按照Java的规则,如果你要想将一个对象放入HashMap中,你的对象的类必须提供hashcode方法,返回一个整数值。

散列计算就是计算元素应该放在数组的哪个元素里。准确的说是放到哪个链表里面。按照Java的规则,如果你要想将一个对象放入HashMap中,你的对象的类必须提供hashcode方法,返回一个整数值。比如String类就有如下方法:

  1. public int hashCode() {  
  2.         int h = hash;  
  3.         int len = count;  
  4.         if (h == 0 && len > 0) {  
  5.             int off = offset;  
  6.             char val[] = value;  
  7.  
  8.             for (int i = 0; i < len; i++) {  
  9.                 h = 31*h + val[off++];  
  10.             }  
  11.             hash = h;  
  12.         }  
  13.         return h;  
  14.     } 

注意上面的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进制。这个循环可以抽出来单独作为计算进制的好工具:

  1. public static void main(String[] args) {  
  2.         int[] a={1,0};  
  3.         System.out.println(calculate(2,a));  
  4.     }  
  5.  
  6.     private static int calculate(int radix,int[] a){  
  7.         int sum = 0;  
  8.         for(int i=0;i<a.length;++i){  
  9.             sum = sum*radix+a[i];  
  10.         }  
  11.         return sum;  
  12.     } 

静态方法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的场合提高性能,不过似乎用处不多。

好了,终于扯完了String.hashCode的话题。现在继续回到HashMap的数组元素位置计算上来。

 

原文链接:http://blog.csdn.net/sheismylife/article/details/7351005

【编辑推荐】

  1. Java HashMap分析之一:基本结构
  2. Java集合框架总结:Set接口的使用
  3. Java的位移运算巧方法
  4. Java7的一个新类JLayer:装饰的Swing组件
  5. 关于Java中内存溢出的解决办法
责任编辑:林师授 来源: sheismylife的博客
相关推荐

2015-08-10 15:12:27

Java实例源码分析

2023-02-13 08:01:49

HashHashMapint

2016-09-12 14:33:20

javaHashMap

2021-09-10 06:50:03

HashMapHash方法

2012-03-15 17:18:33

JavaHashMap

2012-03-15 16:12:57

JavaHashMap

2018-04-19 14:11:50

2012-02-15 10:34:29

JavaJava Socket

2021-11-08 15:06:15

鸿蒙HarmonyOS应用

2011-05-27 14:03:22

网站流量

2022-03-04 15:43:36

文件管理模块Harmony鸿蒙

2022-05-09 11:52:38

Java卡片服务卡片

2021-10-11 11:58:41

Channel原理recvq

2021-12-01 07:02:16

虚拟化LinuxCPU

2021-10-28 19:27:08

C++指针内存

2021-06-29 08:28:12

算法顺序表数据

2021-02-15 15:36:20

Vue框架数组

2020-10-15 14:10:51

网络攻击溯源

2021-01-18 05:33:08

机器学习前端算法

2021-12-17 07:47:37

TCASwiftUI 运作
点赞
收藏

51CTO技术栈公众号