【问题标题】:IdentityHashMap NullPointerExceptionIdentityHashMap NullPointerException
【发布时间】:2014-09-15 16:21:29
【问题描述】:

我遇到了一个问题。我使用了一个 IdentityHashMap。我将这些条目放入其中 {150=1, 79=3, 345=6, 88=5, 50=4, 3=7, 24=2}。当键为 50、150 时,我尝试获取它们的值.但我得到了 java.lang.NullPointerException。我不知道为什么。请帮我修复它。非常感谢。

这是我的代码:

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

    }

}

【问题讨论】:

  • NPE 被抛出哪一行?这也编译吗? --- 结果[1] = map.get( numbers[tail]i );
  • 为什么要使用IdentityHashMap?此外,您的方法修改了传入的 numbers 变量 - 这有点奇怪。
  • numbers[tail]i 应该是什么?
  • 这段代码中没有任何东西可以抛出NullPointerException
  • @njzk2 这完全是个谎言!任何人都应该清楚,至少result[x] = map.get( ... ) 可以抛出NPE,因为resultint[]

标签: java nullpointerexception hashmap


【解决方案1】:

您被 JVM 的 int 缓存池所吸引,该缓存池在自动装箱 int 时会自动使用。结果是低 int 值将共享同一个装箱 int 实例,但较大值不会。 150 在此缓存范围之外,因此插入到映射中的键与用于查找值的实例不同。

作为证据,运行以下代码:

    Integer a = 150;
    Integer b = 150;

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

人们会期望这两个值具有相同的身份哈希码,但事实并非如此。在我的测试运行中,输出是:

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

对涵盖此行为的 JLS 5.1.7 的引用。

理想情况下,装箱一个给定的原始值 p,总是会产生一个相同的引用。在实践中,使用现有的实现技术这可能是不可行的。上述规则是一种务实的妥协。上面的最后一个条款要求某些常见的值总是被装箱到无法区分的对象中。实现可能会懒惰地或急切地缓存这些。对于其他值,此公式不允许程序员对装箱值的身份进行任何假设。这将允许(但不要求)共享部分或全部这些引用。

要解决此问题,您应该避免完全自动装箱。但作为另一个证明是这个缓存让你失望的另一个例子,你可以在运行测试时调整 int 缓存的大小。

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

设置此标志后,您的测试程序将不会抛出 NullPointerException 并且会按照您预期的方式运行。无论如何,最多可达 4096 的键值;)

【讨论】:

  • +1 用于解释实际问题。此外,使用普通的HashMap 也可以解决此问题。
猜你喜欢
  • 2018-06-13
  • 2011-09-23
  • 2014-05-19
  • 2015-06-17
  • 2010-10-24
  • 2013-06-07
  • 1970-01-01
  • 2016-02-27
相关资源
最近更新 更多