现象:
计费和账户的交互通过Map来交互,基本数据格式如下{"pp900_88",20,"pp900_61",2……}
在不同的取值情况下,较多数据返回了相同的价格结果,导致计算价格错误。
应用场景:
产品计算价格时,使用cache缓存了价格结果数据,cache的key值是传入map的hashCode,本意是要实现完全相同的Map传入值从缓存取数据,减少数据库的访问。
原因分析:
一。通过如下代码模拟线上应用:
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);
}
结果如下:
{-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值相加,即
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拼接字符串。
分享到:
相关推荐
一. 理论准备 ...HashMap的值是没有顺序的,它是按照key的HashCode来实现的,对于这个无序的HashMap我们要怎么来实现排序呢?参照TreeMap的value排序。 Map.Entry返回Collections视图。 二. key排序 Tr
实际上,hashcode根本不能代表object的内存地址。
深入 HashCode 方法~~~~~
hashcode是用来查找的,如果你学过数据结构就应该知道,在查找和排序这一章有……
主要介绍了浅谈Java中hashCode的正确求值方法,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下
hashcode的作用.doc hashcode的作用.doc hashcode的作用.doc
1.hashcode是用来查找的,如果你学过数据结构就应该知道,在查找和排序这一章有 例如内存中有这样的位置 0 1 2 3 4 5 6 7 而我有个类,这个类有个字段叫ID,我要把这个类存放在以上8个位置之一,如果不用hashcode...
1,如果两个对象相同,那么它们的hashCode值一定要相同; 2,如果两个对象的hashCode相同,它们并不一定相同 上面说的对象相同指的是用eqauls方法比较。 3,HashCode码不唯一
Java重写equals同时需要重写hashCode的代码说明,以及如何重写hashCode方法,此代码演示按照effective java书籍说明的重写思路。代码中演示了使用集合存储对象,并且对象作为key,需重写equals和hashCode.
重写equals和hashcode方法,学习和进步
这里是一个文档,里边讲解了hashCode与equals方法使用,大家要是不明白,可以去看看
equals()和hashcode()这两个方法都是从object类中继承过来的。当String 、Math、还有Integer、Double。。。。等这些封装类在使用equals()方法时,已经覆盖了object类的equals()方法.
hashcode、equals、==总结1简单总结.txt,他们之间的区别
PPT浅析hashcode定义和作用;和简单的代码演示PPT.很简单的
java中hashCode()的理解
java中Hashcode的作用
深入HashCode 最近学习HashCode的小结与整理,希望对大家有帮助
利用反射绕过编译器和hashcode高级应用
Map接口定义了四种类型的方法,每个Map都包含这些方法。...remove(Object key) 从Map中删除键和关联的值。 put(object key,Object value) 将指定值与指定键相关联。 clear() 从Map虽删除所有映射。
本文介绍了Java语言不直接支持关联数组,可以使用任何对象作为一个索引的数组,但在根Object类中使用 hashCode()方法明确表示期望广泛使用HashMap。理想情况下基于散列的容器提供有效插入和有效检索;直接在对象模式...