11

I ran the follow script(java), and it gave me the weird result. Does anyone can help to explain?

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}));
        }
    }
}

Log Result(they are different from each other):

//...
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
//...

---- Background ----

I wanted to used my own keyGenrator for @Cacheable annotation(Spring & ehCache).

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

In this case, I find the cache are always missed.

Then I have to change to this:

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

Thank you

Salty Egg
  • 185
  • 12

1 Answers1

12

It's because hashCode for int[] is not overridden. There is no reason why two instances of int[] should have the same hashCode, even if the entries are the same.

Try this:

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

You will almost certainly see two different integers.

A good way to use Objects.hash with arrays is to pass Arrays.hashCode(array) instead of the actual array. In your case you could do:

Objects.hash("getDemoCache", "1", Arrays.hashCode(new int[]{1, 2}))
Paul Boddington
  • 37,127
  • 10
  • 65
  • 116
  • 1
    Thank you, @pbabcdefp, sooo much! You save my life. Your explanation is very clear! – Salty Egg Apr 29 '15 at 22:08
  • Aha! Thanks! I had a similar problem but I thought `Stream.mapToInt()` would've worked. Apparently it returns an `IntStream`, so I needed call `stream.boxed().toArray()` in order to convert my integers into a list of objects. Only then I received consistent hash codes. – Nicholas Miller Feb 18 '18 at 04:42