刚才debug追堆栈的时候发现一个很奇怪的问题

我用IE8和Google的浏览器访问同一个地址

Action的 scope="session" 也设置了

而且两个浏览器提交的参数map也是互相独立的

不过很奇怪的一个 两个Action对象的hashmap是不同的
但是它们的对象变量 paraterMap 的 哈希值 居然是一个

我大不解!
( 找到原因以后发现这个问题其实只是一个好多年没有再提起的基础问题 )
不过发现确实有朋友在网上说这个问题曾经引发过bug

Java中的hashCode()方法是一个比较特殊的地方
Object类中的hashCode是一个本地方法
public native int hashCode();
即使查看源码你也找不到它的实现, 因为它不是一个java编写的方法
此方法比较两个对象的内存地址是不是相等

6.1 覆写的HashCode方法
很多API中的子类会覆盖这个方法,最典型的应该是String类, 在String类中
   /**
     * Returns a hash code for this string. The hash code for a
     * <code>String</code> object is computed as
     * <blockquote><pre>
     * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
     * </pre></blockquote>
     * using <code>int</code> arithmetic, where <code>s[i]</code> is the
     * <i>i</i>th character of the string, <code>n</code> is the length of
     * the string, and <code>^</code> indicates exponentiation.
     * (The hash value of the empty string is zero.)
     *
     * @return a hash code value for this object.
     */
    public int hashCode() {
        int h = hash;
        if (h == 0) {
            int off = offset;
            char val[] = value;
            int len = count;

for (int i = 0; i < len; i++) {
                h = 31*h + val[off++];
            }
            hash = h;
        }
        return h;
}
可以看到, String类是使用它的 value值作为参数然后进行运算得出hashcode的
换句话说, 只要值相同的String不管是不是一个对象,hash值全部相等

也就是说运行下面的代码你会看见完全相同的hashcode
至于在不同的两台电脑上会不会相同我不知道,因为参与运算的off偏移量可能会不同

6.2 小心使用HashMap对象的hashcode
这是一个极为危险的行为!

public final int hashCode() {
            return (key==null ? 0 : key.hashCode()) ^
                   (value==null ? 0 : value.hashCode());
        }

在HashMap类中, 如果HashMap对象的内部对象是空的, 则hashcode 一定是 0
如果非空, 则遍历容器中的全部对象
然后取key的hashcode和value的hashcode 按位异或运算,然后把他们依次相加

也就是说, 如果你的两个HashMap的key和value全部相同的话, 那么, 它们的hashcode就是相同的

HashMap map1 = new HashMap();
                map1.put("test", "testValue");
                map1.put("test1", "testValue1");
                map1.put("test2", "testValue2");
                
                HashMap map2 = new HashMap();
                map2.put("test", "testValue");
                map2.put("test1", "testValue1");
                map2.put("test2", "testValue2");
                
                System.out.println(map1.hashCode());
                System.out.println(map2.hashCode());

下面代码的输出值是相等的

所以! 在任何时候! 不要使用HashMap或一些特殊容器的Hashcode作为key来进行缓存

以下内容转自
http://dingjob.javaeye.com/blog/696768
http://dingjob.javaeye.com/blog/696768
之所以写了两个连接,是因为douban上那个添加连接会携带 a href 锚点标签
我就是想看看如果我不用这个它会不会自动判断是链接地址,然后自己给加上
很满意, 豆瓣做的不脑残╮(╯_╰)╭

2010-06-22
Map的HashCode做缓存key值引发的重大bug
文章分类:Java编程
现象:

计费和账户的交互通过Map来交互,基本数据格式如下{"pp900_88",20,"pp900_61",2……}

在不同的取值情况下,较多数据返回了相同的价格结果,导致计算价格错误。

应用场景:

产品计算价格时,使用cache缓存了价格结果数据,cache的key值是传入map的hashCode,本意是要实现完全相同的Map传入值从缓存取数据,减少数据库的访问。

原因分析:

一。通过如下代码模拟线上应用:

Java代码
1.public static void main(String[] args) {
2. HashMap map = new HashMap();
3.
4. for(int i = 0 ; i < 100 ; i ++){
5.
6. HashMap m1 = new HashMap();
7.
8. m1.put("pp900_88", i);
9.
10. m1.put("pp900_59", 30);
11.
12. m1.put("pp900_62", 6);
13.
14. m1.put("pp900_63", 4);
15.
16. m1.put("pp900_60", "y");
17.
18. m1.put("pp900_61", i);
19.
20. int hs = m1.hashCode();
21.
22. map.put(hs, map.get(hs)+","+i);
23. // System.out.println(i+"==="+m1.hashCode());
24. }
25. System.out.println(map.size());
26. System.out.println(map);
27. }
  public static void main(String[] args) {
        HashMap map = new HashMap();

for(int i = 0 ; i < 100 ; i ++){

HashMap m1 = new HashMap();

m1.put("pp900_88", i);

m1.put("pp900_59", 30);

m1.put("pp900_62", 6);

m1.put("pp900_63", 4);

m1.put("pp900_60", "y");

m1.put("pp900_61", i);

int hs = m1.hashCode();

map.put(hs, map.get(hs)+","+i);
            // System.out.println(i+"==="+m1.hashCode());
        }
        System.out.println(map.size());
        System.out.println(map);
    } 结果如下:

Java代码
1.{-479160017=null,56,57,58,59,60,61,62,63,
2. -479160049=null,40,41,42,43,44,45,46,47,
3. -479160033=null,48,49,50,51,52,53,54,55,
4. -479160129=null,0,1,2,3,4,5,6,7,64,65,66,67,68,69,70,71,
5. -479160097=null,16,17,18,19,20,21,22,23,80,81,82,83,84,85,86,87,
6. -479160113=null,8,9,10,11,12,13,14,15,72,73,74,75,76,77,78,79,
7. -479160065=null,32,33,34,35,36,37,38,39,96,97,98,99,
8. -479160081=null,24,25,26,27,28,29,30,31,88,89,90,91,92,93,94,95}
{-479160017=null,56,57,58,59,60,61,62,63,
 -479160049=null,40,41,42,43,44,45,46,47,
 -479160033=null,48,49,50,51,52,53,54,55,
 -479160129=null,0,1,2,3,4,5,6,7,64,65,66,67,68,69,70,71,
 -479160097=null,16,17,18,19,20,21,22,23,80,81,82,83,84,85,86,87,
 -479160113=null,8,9,10,11,12,13,14,15,72,73,74,75,76,77,78,79,
 -479160065=null,32,33,34,35,36,37,38,39,96,97,98,99,
 -479160081=null,24,25,26,27,28,29,30,31,88,89,90,91,92,93,94,95}

可以看到,重复是很有规律的,连续7、8个数据都是重复的,当然在真实情况下重复概率不会这么高(因为Map的其他key-value值不太可能完全相同)

二。分析hashCode的产生

HashMap的hashCode根据key和value值来计算hashCode,最后将各个元素的hashCode值相加,即

Java代码
1.public final int hashCode() {
2. return (key==null ? 0 : key.hashCode()) ^
3. (value==null ? 0 : value.hashCode());
4. }
 public final int hashCode() {
            return (key==null ? 0 : key.hashCode()) ^
                   (value==null ? 0 : value.hashCode());
        }

以 m1.put("pp900_88", 1); m1.put("pp900_61", 1);和

m1.put("pp900_88", 2); m1.put("pp900_61", 2);为例子:得到的key-Value的hashCode值如下

key key的hashCode value的hashCode Map的hashCode(key^value)

pp900_88 -79859962 1 -79859961

pp900_61 -79860031 1 -79860032
  pp900_88 -79859962 2 -79859964
  pp900_61 -79860031 2 -79860029
 
显然根据Map的hash值算法, Map的hashCode相加:第一行+第二行=第三行+第四行,这样产生重复数据也在所难免了,因为hashCode本来就不保证不同的输入值不会产生相同的结果。JSL的约束是对于相同的对象,必须产生相同的hashCode。
结论和改进措施:
1.不建议对结果进行缓存,结果缓存会带来很多问题,比如哪些数据变更需要刷新哪些缓存,缓存最好对原始纪录值进行缓存。
2.key值不采用hashCode算法,直接改为使用各个key-value的String拼接字符串。

千万不要误用 java 中的 HashCode 方法的更多相关文章

  1. 浅谈Java中的hashcode方法

    哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: 1 public native int hashCode(); 根据 ...

  2. 【转】浅谈Java中的hashcode方法(这个demo可以多看看)

    浅谈Java中的hashcode方法 哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: public native i ...

  3. 【转】浅谈Java中的hashcode方法

    哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: public native int hashCode(); 根据这个 ...

  4. Java中的hashcode方法

    一.hashCode方法的作用 对于包含容器类型的程序设计语言来说,基本上都会涉及到hashCode.在Java中也一样,hashCode方法的主要作用是为了配合基于散列的集合一起正常运行,这样的散列 ...

  5. 浅谈Java中的hashcode方法(转)

    原文链接:http://www.cnblogs.com/dolphin0520/p/3681042.html 浅谈Java中的hashcode方法 哈希表这个数据结构想必大多数人都不陌生,而且在很多地 ...

  6. 浅谈Java中的hashcode方法(转载)

    哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: 1 public native int hashCode(); 根据 ...

  7. 彻底理解Java中的hashcode方法(转)

    本文转自http://www.importnew.com/18851.html 哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有 ...

  8. 浅谈Java中的hashcode方法以及equals方法

    哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: public native int hashCode(); 根据这个 ...

  9. java中的hashcode方法作用以及内存泄漏问题

    本文装载:http://hi.baidu.com/iduany/item/6d66dfc9d5f2da1650505870 hashCode()方法的作用&使用分析 一直以来都想写篇文章来说明 ...

随机推荐

  1. page-cache层以及各种标志位之间的转换

    对真实文件系统层,算是懂了,但是vfs层以及block层还是有点生疏呢,最近要好好分析一下了. page-cache层主要关注文件读写时的行为,包括页的状态之间的变化,何时变脏,何时变成writeba ...

  2. sqlserver字段类型详解(转)

    bit    整型 bit数据类型是整型,其值只能是0.1或空值.这种数据类型用于存储只有两种可能值的数据,如Yes 或No.True 或False .On 或Off. 注意:很省空间的一种数据类型, ...

  3. acl拒绝访问流量

        interface Ethernet0/0 ip address 12.1.1.2 255.255.255.0 ip access-group 10 in half-duplex   R1# ...

  4. 查询EBS请求日志的位置和名称

    select * from FND_CONCURRENT_PROGRAMS_VL fcp where fcp.USER_CONCURRENT_PROGRAM_NAME like '%CUX%XXXX% ...

  5. 2015年新版C#从入门到精通(第2版)视频教学录像【无水印版】

    <c#从入门到精通(第2版)>以零基础讲解为宗旨,用实例引导读者学习,深入浅出地介绍了c#的相关知识和实战技能.<c#从入门到精通(第2版)>第1篇[c#语言基础]主要讲解c# ...

  6. JSTL 标签库 使用

    标签库概要: 一.C标签库介绍 1.1.<c:> 核心标签库  JSTL 核心标签库(C标签)标签共有13个,功能上分为4类:1.表达式控制标签:out.set.remove.catch2 ...

  7. 进程&信号&管道实践学习记录

    程序分析 exec1.c & exect2.c & exect3.c 程序代码 (以exect1.c为例,其他两个结构类似) #include <stdio.h> #inc ...

  8. 游戏世界之Unity3D的基础认识

    1.写在前面 Unity3D是由Unity Technologies开发的一个让你轻松创建诸如三维视频游戏.建筑可视化.实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏 ...

  9. git点滴的积累

    git的基本学习的网址: http://www.yiibai.com/git/git_update_operation.html 0.git首次上传代码 http://www.cnblogs.com/ ...

  10. Linq 中查询一个表中指定的字段

    //Linq中查询一个表中指定的几个字段: ); // FindAllItems()为查询对应表的所有数据的方法: // Where 里面为查询条件 // Select 为查询的筛选条件 new{} ...