转载自:http://blog.csdn.net/hengyunabc/article/details/7198533

JDK6的源码:

[java] view
plain
copy

  1. /**
  2. * Returns a hash code for this string. The hash code for a
  3. * <code>String</code> object is computed as
  4. * <blockquote><pre>
  5. * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
  6. * </pre></blockquote>
  7. * using <code>int</code> arithmetic, where <code>s[i]</code> is the
  8. * <i>i</i>th character of the string, <code>n</code> is the length of
  9. * the string, and <code>^</code> indicates exponentiation.
  10. * (The hash value of the empty string is zero.)
  11. *
  12. * @return  a hash code value for this object.
  13. */
  14. public int hashCode() {
  15. int h = hash;
  16. if (h == 0) {
  17. int off = offset;
  18. char val[] = value;
  19. int len = count;
  20. for (int i = 0; i < len; i++) {
  21. h = 31*h + val[off++];
  22. }
  23. hash = h;
  24. }
  25. return h;
  26. }

以字符串"123"为例:

字符'1'的ascii码是49

hashCode = (49*31 + 50)*31 + 51

或者这样看:

hashCode=('1' * 31 + '2' ) * 31 + '3'

可见实际可以看作是一种权重的算法,在前面的字符的权重大。

这样有个明显的好处,就是前缀相同的字符串的hash值都落在邻近的区间。

好处有两点:

1.可以节省内存,因为hash值在相邻,这样hash的数组可以比较小。比如当用HashMap,以String为key时。

2.hash值相邻,如果存放在容器,比好HashSet,HashMap中时,实际存放的内存的位置也相邻,则存取的效率也高。(程序局部性原理)

以31为倍数,原因了31的二进制全是1,则可以有效地离散数据。

最后看下,两个字符串,由Eclipse生成的代码是如何计算hash值的:

[java] view
plain
copy

  1. public class Name{
  2. String firstName;
  3. String lastName;
  4. @Override
  5. public int hashCode() {
  6. final int prime = 31;
  7. int result = 1;
  8. result = prime * result
  9. + ((firstName == null) ? 0 : firstName.hashCode());
  10. result = prime * result
  11. + ((lastName == null) ? 0 : lastName.hashCode());
  12. return result;
  13. }
  14. @Override
  15. public boolean equals(Object obj) {
  16. if (this == obj)
  17. return true;
  18. if (obj == null)
  19. return false;
  20. if (getClass() != obj.getClass())
  21. return false;
  22. Name other = (Name) obj;
  23. if (firstName == null) {
  24. if (other.firstName != null)
  25. return false;
  26. } else if (!firstName.equals(other.firstName))
  27. return false;
  28. if (lastName == null) {
  29. if (other.lastName != null)
  30. return false;
  31. } else if (!lastName.equals(other.lastName))
  32. return false;
  33. return true;
  34. }
  35. }

可见,还是以31为倍数, hashCode = firstName.hashCode() * 31 + lastName.hashCode() 。

BTW:Java的字符串的hash做了缓存,第一次才会真正算,以后都是取缓存值。

eclipse生成的equals函数质量也很高,各种情况都考虑到了。

总结:字符串hash函数,不仅要减少冲突,而且要注意相同前缀的字符串生成的hash值要相邻。

Java中String的hash函数分析的更多相关文章

  1. Java中String连接性能的分析【转】

    [转]http://www.blogjava.net/javagrass/archive/2010/01/24/310650.html 总结:如果String的数量小于4(不含4),使用String. ...

  2. Java中String连接性能的分析

    总结:如果String的数量小于4(不含4),使用String.concat()来连接String,否则首先计算最终结果的长度,再用该长度来创建一个StringBuilder,最后使用这个String ...

  3. Java中String的替换函数:replace与replaceAll的区别

    例如有如下x的字符串  String x = "[kllkklk\\kk\\kllkk]"; 要将里面的"kk"替换为++,可以使用两种方法得到相同的结果  r ...

  4. java中string.trim()函数的使用

    java中string.trim()函数的的作用是去掉字符串开头和结尾的空格,防止不必要的空格导致的错误. public static void main(String arg[]){ String ...

  5. OC与c混编实现Java的String的hashcode()函数

    首先,我不愿意大家需要用到这篇文章里的代码,因为基本上你就是被坑了. 起因:我被Java后台人员坑了一把,他们要对请求的参数增加一个额外的字段,字段的用途是来校验其余的参数是否再传递过程中被篡改或因为 ...

  6. java中String类型变量的赋值问题

    第一节 String类型的方法参数 运行下面这段代码,其结果是什么? package com.test; public class Example { String str = new String( ...

  7. 探秘Java中String、StringBuilder以及StringBuffer

    探秘Java中String.StringBuilder以及StringBuffer 相信String这个类是Java中使用得最频繁的类之一,并且又是各大公司面试喜欢问 到的地方,今天就来和大家一起学习 ...

  8. java中String类、StringBuilder类和StringBuffer类详解

    本位转载自http://www.cnblogs.com/dolphin0520/p/3778589.html  版权声明如下: 作者:海子 出处:http://www.cnblogs.com/dolp ...

  9. 【转载】 Java中String类型的两种创建方式

    本文转载自 https://www.cnblogs.com/fguozhu/articles/2661055.html Java中String是一个特殊的包装类数据有两种创建形式: String s ...

随机推荐

  1. 352[LeetCode] Data Stream as Disjoint Intervals

    Given a data stream input of non-negative integers a1, a2, ..., an, ..., summarize the numbers seen ...

  2. LeetCode - 566. Reshape the Matrix (C++) O(n)

    1. 题目大意 根据给定矩阵,重塑一个矩阵,r是所求矩阵的行数,c是所求矩阵的列数.如果给定矩阵和所求矩阵的数据个数不一样,那么返回原矩阵.否则,重塑矩阵.其中两个矩阵中的数据顺序不变(先行后列). ...

  3. Ext JS 6学习文档-第5章-表格组件(grid)

    Ext JS 6学习文档-第5章-表格组件(grid) 使用 Grid 本章将探索 Ext JS 的高级组件 grid .还将使用它帮助读者建立一个功能齐全的公司目录.本章介绍下列几点主题: 基本的 ...

  4. struts2之form标签theme属性详解

    struts2中theme属性包括xhtml,html,simple,ajax .默认是xhtml theme:设置struts2标签的主题,默认为xhtml. theme=xhtml时:会默认额外生 ...

  5. 今年暑假不AC (贪心)

    Description “今年暑假不AC?” “是的.” “那你干什么呢?” “看世界杯呀,笨蛋!” “@#$%^&*%...” 确实如此,世界杯来了,球迷的节日也来了,估计很多ACMer也会 ...

  6. Python 元组 集合

    1. 元组 >>> a = (1,2,3,4,5) >>> b = list(a) #转换成列表对象, 可以更改 >>> b [1, 2, 3, ...

  7. Swift-枚举enum理解

    //定义一个枚举 //枚举的语法,enum开头,每一行成员的定义使用case关键字开头,一行可以定义多个关键字 enum CompassPoint { case North case South ca ...

  8. css那些事儿2 经典两列布局

    <!DOCTYPE html> <html> <head> <title></title> <link rel="style ...

  9. 【Docker 命令】- login 命令

    docker login : 登陆到一个Docker镜像仓库,如果未指定镜像仓库地址,默认为官方仓库 Docker Hub docker logout : 登出一个Docker镜像仓库,如果未指定镜像 ...

  10. Bookmark Sentry – 检查重复、删除死链书签 Chrome扩展

    Bookmark Sentry 的用处,就是 处理重复的收藏夹的死链 . 重复链收藏.具体,请百度. Bookmark Sentry 下载 :  https://files.cnblogs.com/f ...