现象:
计费和账户的交互通过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拼接字符串。
分享到:
相关推荐
- 对于不同的类,默认情况下,`hashCode()` 方法的实现可能会有所不同,但通常会依赖于对象的一些关键属性来生成一个整数值作为 `HashCode`。 2. **自定义类中的 HashCode 实现**: - 当我们自定义一个类时,通常...
return Objects.hashCode(key) ^ Objects.hashCode(value); } equals 方法和 hashCode 方法都是用于比较两个对象是否相等的,但它们的实现方式不同。equals 方法是比较两个对象的内容是否相等,而 hashCode 方法是...
hashCode 的用法详解 hashCode 是一种用于查找和排序的机制,在数据结构中 plays a crucial role。下面我们将对 hashCode 的用法进行详细的解释。 hashCode 的作用 hashCode 的主要作用是用于查找和排序。在查找...
在Java中,`hashCode()` 方法是 `Object` 类的一个重要成员方法,它返回一个整数,这个整数通常用来表示对象的哈希值。哈希值在Java集合框架中扮演着至关重要的角色,尤其是在散列表(如 `HashMap` 和 `Hashtable`)...
在哈希表中,`hashCode()`被用来计算对象存储的位置,因为哈希表通过对象的哈希值来确定其存储位置,从而实现快速查找。理想情况下,不同的对象应有不同的哈希码,但相同的对象(根据`equals()`方法判断相等)必须...
浅谈Java中hashCode的正确求值方法 hashCode是一种常用的散列函数,在Java中它是一个对象的整数表示,用于标识对象的唯一性。在Java中,每个对象都有一个hashCode,这个hashCode可以通过hashCode()方法来获取。...
1. 在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,则对该对象调用hashCode方法多次,它必须始终如一地返回同一个整数。 2. 如果两个对象根据equals(Object o)方法是相等的,...
这是因为,如果两个相等的对象具有不同的`hashCode`值,可能会导致在某些场景下出现问题,比如在`HashSet`或`HashMap`中无法正确识别相等的对象。 #### 5. 示例代码解析 以下是一段示例代码,展示了如何使用`...
一. 理论准备 ...HashMap的值是没有顺序的,它是按照key的HashCode来实现的,对于这个无序的HashMap我们要怎么来实现排序呢?参照TreeMap的value排序。 Map.Entry返回Collections视图。 二. key排序 Tr
在编程领域,`Map`是一种数据结构,它存储键值对,允许我们通过键来查找对应的值。在各种编程语言中,如Java、C++、Python等,都有类似的概念。`Map`通常用于关联特定的值与特定的键,使得在处理大量数据时能快速...
在Java编程语言中,`equals()` 和 `hashCode()` 方法是Object类中的两个核心方法,所有类都默认继承自Object类。这两个方法在处理对象比较和集合操作时起着至关重要的作用。当我们创建自定义类并需要对对象进行精确...
然而,SHA-256是一个强加密算法,如果我们想根据图片URL的MD5值来查找缓存,我们需要自定义这个key生成过程。 为实现这个目标,我们需要创建一个新的`KeyGenerator`类,这里称为`SafeKeyGenerator`,并让它继承自...
Java中的Map映射机制是Java集合框架的重要组成部分,它提供了键值对的存储方式,使得可以通过键来查找和操作对应的值。Map接口是所有映射类的基础,它定义了多种方法来实现对键值对的操作。 Map接口的核心方法包括...
Map集合不按照特定顺序存储元素,而是通过键(Key)来查找对应的值(Value)。以下是对Map接口及其常用实现类的详细说明: 1. **声明Map**: 创建Map实例时,通常使用HashMap作为默认实现。例如: ```java Map, ...
- `put(K key, V value)`: 将指定的键值对放入Map中,如果键已经存在,则替换旧值。 - `get(Object key)`: 返回与指定键关联的值,如果不存在则返回null。 - `containsKey(Object key)`: 检查Map是否包含指定的键。 ...
Map不同于List,List是以索引来访问元素,而Map则是通过键(key)来查找对应的值(value)。Map接口定义了一系列方法,使得我们可以对键值对进行插入、删除、修改和查找等操作。 1. **创建Map实例**: 创建一个Map...
其中,`equals(Object o)`和`hashCode()`方法用于比较Map的等价性,确保了Map的正确比较和存储。插入和删除元素的操作由`put(Object key, Object value)`、`remove(Object key)`以及`clear()`等方法完成。`putAll...
反之,如果两个对象的`hashCode()`值相同,则还需要进一步通过`equals()`方法来确定这两个对象是否真正相等。 #### 实现细节 在上面的代码示例中,`Person1`类重写了`hashCode()`方法: ```java public int ...
- 如果两个对象不相等(即`equals()`返回`false`),它们的`hashCode()`值不一定不同,但最好尽量让它们不同,以减少哈希冲突。 #### `equals()`方法 `equals()`方法同样定义于`Object`类中,用于判断两个对象是否...