为什么Objects.hash()对于相同的输入返回不同的值?

11

我运行了下面这段脚本(Java),结果却很奇怪。有人能帮忙解释一下吗?

import java.util.Objects;
import org.apache.log4j.Logger;

public class CacheTester {

private static final Logger log = Logger.getLogger(CacheTester.class);

    @Test
    public void hashCodeTest() {
        for (int i = 0; i < 50; i++) {
            // if I remove the third parameter, it works fine
            log.info(Objects.hash("getDemoCache", "1", new int[]{1, 2}));
        }
    }
}

日志结果(它们彼此不同):

//...
2015-04-29 17:43:20 INFO  CacheTester:42 - 1431904540
2015-04-29 17:43:20 INFO  CacheTester:42 - 1859187447
2015-04-29 17:43:20 INFO  CacheTester:42 - -2146933580
2015-04-29 17:43:20 INFO  CacheTester:42 - -2074242201
2015-04-29 17:43:20 INFO  CacheTester:42 - 1363170000
2015-04-29 17:43:20 INFO  CacheTester:42 - 1040980265
2015-04-29 17:43:20 INFO  CacheTester:42 - 1639331053
2015-04-29 17:43:20 INFO  CacheTester:42 - 570765746
2015-04-29 17:43:20 INFO  CacheTester:42 - -2023288896
2015-04-29 17:43:20 INFO  CacheTester:42 - -1892732019
2015-04-29 17:43:20 INFO  CacheTester:42 - 1464306601
2015-04-29 17:43:20 INFO  CacheTester:42 - 921799986
2015-04-29 17:43:20 INFO  CacheTester:42 - 1037804977
//...

---- 背景 ----

我想为 @Cacheable 注解(Spring & ehCache)使用自己的 keyGenerator。

public Object generate(Object target, Method method, Object... params) {
    int key = Objects.hashCode(method.getName(), params);
    log.info("key = " + key);
    return key;
}

在这种情况下,我发现缓存总是无法命中。

那么我必须更改为这个:

public Object generate(Object target, Method method, Object... params) {
    int result = method.getName().hashCode() : 0;
    result = 31 * result + Objects.hashCode(params);
    return result;
}

谢谢你


2
int[].hashCode() 是基于标识的,而不是基于内容的。 - Louis Wasserman
请参见以下链接:https://dev59.com/VHRB5IYBdhLWcg3wAjbR - ericbn
谢谢大家,真的学到了很多!=) - Salty Egg
1个回答

12

这是因为 int[]hashCode 没有被重写。即使条目相同,两个 int[] 实例没有理由具有相同的 hashCode

请尝试这样做:

System.out.println(new int[] {1, 2}.hashCode());
System.out.println(new int[] {1, 2}.hashCode());

你几乎肯定会看到两个不同的整数。

在数组上使用Objects.hash的好方法是传递Arrays.hashCode(array)而不是实际的数组。在你的情况下,你可以这样做:

Objects.hash("getDemoCache", "1", Arrays.hashCode(new int[]{1, 2}))

1
非常感谢你,@pbabcdefp!你救了我的命。你的解释非常清晰! - Salty Egg
啊哈!谢谢!我也遇到了类似的问题,但我认为 Stream.mapToInt() 应该可以解决。显然它返回一个 IntStream,所以我需要调用 stream.boxed().toArray() 将我的整数转换为对象列表。只有这样我才能得到一致的哈希码。 - Nicholas Miller

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接