You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Integer二维数组元素默认非null?空指针问题求助

问题根源与解决方案

核心问题

你对Java二维数组的初始化逻辑理解有误:

  • 执行Integer[][] bucket = new Integer[nums.length+1][1];时,Java会为外层数组的每一个索引位置自动创建一个长度为1的Integer子数组,这些子数组内的元素默认是null(因为Integer是引用类型)。
  • 你原本以为未被赋值的bucket[i]是null,但实际上它们都是已初始化的子数组,只是子数组里的元素没被赋值。这就导致遍历判断bucket[i] != null时,那些从未被freqMap处理过的索引也会进入分支,而它们的bucket[i][0]是null,赋值给int类型的数组元素时触发NullPointerException。
  • 额外问题:你的if (bucket[frequency] == null)判断永远不会成立,因为所有bucket[i]都已被初始化,这个分支完全无效。

修复方案

方案1:修正数组初始化方式

只创建外层数组,不自动初始化内层子数组,让未被处理的bucket[i]保持null,符合你的预期逻辑:

public int[] topKFrequent(int[] nums, int k) {
    Map<Integer, Integer> freqMap = new HashMap<>();
    for(int num : nums) 
        freqMap.put(num, freqMap.getOrDefault(num, 0)+1);
    // 仅初始化外层数组,内层默认是null
    Integer[][] bucket = new Integer[nums.length+1][];
    for(int key : freqMap.keySet()) {
        int frequency = freqMap.get(key);
        if (bucket[frequency] == null) {
            bucket[frequency] = new Integer[1];
        }
        bucket[frequency][0] = key;
    }
        
    int[] res = new int[k];
    int resIdx = 0;
    for(int i = bucket.length-1; i>=0; i--) {
        if(bucket[i] != null) {
            System.out.println(i);
            System.out.println(bucket[i][0]);
            res[resIdx++] = bucket[i][0];
            if(resIdx == k) return res;
        }
    }
    return res;
}

方案2:完善遍历判断逻辑

保留原数组初始化方式,但在遍历的时候同时检查子数组元素是否为null:

// ... 前面代码不变
for(int i = bucket.length-1; i>=0; i--) {
    if(bucket[i] != null && bucket[i][0] != null) {
        System.out.println(i);
        System.out.println(bucket[i][0]);
        res[resIdx++] = bucket[i][0];
        if(resIdx == k) return res;
    }
}
// ...

额外优化:处理同频率的多个元素

当前代码存在逻辑缺陷:如果有多个元素的频率相同,后面的元素会覆盖前面的元素(因为每个bucket[frequency]只有一个存储位置)。建议改用List<Integer>[]来存储同频率的所有元素:

public int[] topKFrequent(int[] nums, int k) {
    Map<Integer, Integer> freqMap = new HashMap<>();
    for(int num : nums) 
        freqMap.put(num, freqMap.getOrDefault(num, 0)+1);
    
    List<Integer>[] bucket = new List[nums.length+1];
    // 初始化每个频率对应的空列表
    for(int i = 0; i < bucket.length; i++) {
        bucket[i] = new ArrayList<>();
    }
    
    // 将元素按频率分组
    for(Map.Entry<Integer, Integer> entry : freqMap.entrySet()) {
        bucket[entry.getValue()].add(entry.getKey());
    }
        
    int[] res = new int[k];
    int resIdx = 0;
    // 从高频率到低频率遍历,收集元素
    for(int i = bucket.length-1; i>=0 && resIdx < k; i--) {
        for(int num : bucket[i]) {
            res[resIdx++] = num;
            if(resIdx == k) break;
        }
    }
    return res;
}

内容的提问来源于stack exchange,提问作者Sophy Tao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 08:39:59