简体   繁体   中英

IdentityHashMap NullPointerException

I came across a problem. I used a IdentityHashMap. I put these entries in it {150=1, 79=3, 345=6, 88=5, 50=4, 3=7, 24=2}.when the keys are 50, 150, I try to get their values. but I got java.lang.NullPointerException. I don't know why. please help me fix it. thank you very much.

here is my code:

 import java.util.IdentityHashMap;
 import java.util.Arrays;
 public class HelloWorld {
     public static int[] twoSum(int[] numbers, int target) {
            int[] result = new int[2];
            if (numbers == null || numbers.length < 2) {
                return result;
            }

            IdentityHashMap<Integer, Integer> map = new IdentityHashMap<Integer, Integer>();
            for (int i = 0; i < numbers.length ; i++) {
                map.put(numbers[i], i+1);
            }

            Arrays.sort( numbers );

            int head = 0;
            int tail = numbers.length - 1;
            while (head < tail) {
                if (numbers[head] + numbers[tail] == target) {

                    result[0] =  map.get( numbers[head] );
                    result[1] =  map.get( numbers[tail]i );
                    return result;
                } else if (numbers[head] + numbers[tail] < target) {
                    head++;
                } else {
                    tail--;
                }
            }
            return result;

        }
      public static void main(String[] args) {
        int[] sorce = {150,24,79,50,88,345,3};
        twoSum(sorce, 200);

    }

}

You are getting caught out by the JVMs int cache pool that is used automatically when auto boxing ints. The result is that low int values will share the same instance of a boxed int, but larger values will not. 150 is outside of this cache range so the key that is inserted into the map is a different instance to the one being used to look the value up.

As evidence, run the following code:

    Integer a = 150;
    Integer b = 150;

    System.out.println("System.identityHashCode(a) = " + System.identityHashCode(a));
    System.out.println("System.identityHashCode(b) = " + System.identityHashCode(b));

One would expect both values to have the same identity hashcode, however they do not. On my test run, the output was:

System.identityHashCode(a) = 1291472364
System.identityHashCode(b) = 1158801519

Reference to the JLS 5.1.7 that covers this behaviour.

Ideally, boxing a given primitive value p, would always yield an identical reference. In practice, this may not be feasible using existing implementation techniques. The rules above are a pragmatic compromise. The final clause above requires that certain common values always be boxed into indistinguishable objects. The implementation may cache these, lazily or eagerly. For other values, this formulation disallows any assumptions about the identity of the boxed values on the programmer's part. This would allow (but not require) sharing of some or all of these references.

To fix this problem, you should avoid auto boxing the key entirely. But as another demonstration that it is this cache that is catching you out, you can resize the int cache when you run the test.

-Djava.lang.Integer.IntegerCache.high=4096

With this flag set, your test program will not throw a NullPointerException and will behave the way that you expected. Up to the key value of 4096 anyway ;)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM