【问题标题】:String array without initial size gives null pointer exception没有初始大小的字符串数组给出空指针异常
【发布时间】:2013-05-21 15:49:53
【问题描述】:

我只是在检查一些 OCJP 问题,并在字符串数组初始化和异常期间遇到了这种差异。

案例 1

try {
    String[][] b = new String[10][10]; // 1
    System.out.println(b[0][0]);       // 2
} catch (Exception e) {
    System.out.println("Exception during array 'b' initialization");
        e.printStackTrace();
}

案例 2

try {
    String[][] a = new String[10][]; // 3
    System.out.println(a[0][0]);     // 4
} catch (Exception e) {
    System.out.println("Exception during array 'a' initialization");
    e.printStackTrace();
}

第 2 行不会引发任何异常,而第 4 行会引发空指针异常。 第 2 行确实将值输出为 null

指定数组大小和不指定数组大小时,java初始化的默认值有区别吗?

【问题讨论】:

    标签: java arrays nullpointerexception


    【解决方案1】:

    这会将a 的类型设置为数组数组:

    String[][] a
    

    当你写作时

    String[][] a = new String[10][];
    

    你初始化了外部数组,但你没有创建内部数组,所以a[0]就是null

    当你写作时

    String[][] b = new String[10][10];
    

    运行时还创建内部数组。它被描述为here in the specification

    在运行时,数组创建表达式的计算表现为 如下:

    如果没有维度表达式,那么一定有一个数组 初始化器。

    新分配的数组将使用提供的值进行初始化 由第 10.6 节中所述的数组初始值设定项。

    数组初始化器的值变成数组的值 创作表达。

    否则,没有数组初始化器,并且:

    首先,从左到右计算维度表达式。如果有的话 的表达式求值突然完成,表达式 它的权利不被评估。

    接下来,检查维度表达式的值。如果 任何 DimExpr 表达式的值小于零,则 抛出 NegativeArraySizeException。

    接下来,为新数组分配空间。如果不足 分配数组的空间,数组创建的评估 表达式通过抛出 OutOfMemoryError 突然完成。

    然后,如果出现单个 DimExpr,则创建一维数组 指定长度,并且数组的每个组件是 初始化为其默认值(§4.12.5)。

    否则,如果出现 n 个 DimExpr 表达式,则创建数组 有效地执行一组深度为 n-1 的嵌套循环来创建 隐含的数组。

    一个多维数组不需要有相同长度的数组 每个级别。

    【讨论】:

    • and each component of the array is initialized to its default value 所以第 3 行应该分配 10 1-D arrays 并将 null 作为其每个元素的值,对吧?与第 1 行的情况相同。我说的对吗?
    • 它将 null 分配给 a[0]a[1] 等。而第 1 行将 null 分配给 b[0][0]b[0][1] 等。
    【解决方案2】:
    String[][] a = new String[3][];
    

    相当于:

    String[] a1 = null;
    String[] a2 = null;
    String[] a3 = null;
    String[][] a = {a1, a2, a3};
    

    a[0][0] 类似于a1[0],它会抛出NPE。


    你有两个选择:

    • 将数组定义为:
    String[][] a = new String[3][3];
    
    • 或者在a中创建新数组:
    a[0] = new String[2];
    a[1] = new String[4];
    a[2] = new String[3];
    

    请注意,使用后一种方法,您将能够为内部数组设置不同的大小。

    【讨论】:

      【解决方案3】:

      很好的发现。当你用两个参数初始化一个二维数组时,会发生什么:

      String[][] a = new String[5][5]
      

      但是当你指定第二个界限时,会发生什么:

      String[][] a = new String[5][];
      

      在您的第 4 行中,您会得到确切的 NullPointerException,因为:

      String[][] a = new String[10][];
      System.out.println(a[0][0]); // << a[0] is null!
      

      但是为什么你甚至需要这种行为呢?它很简单。它适用于二维数组中的每个元素可以具有不同数量的元素的情况。潜在的用例场景是:

      这种行为有很多很好的用例,例如优先级队列(每个优先级可以在队列中有不同数量的项目)、哈希表(它的溢出部分)等。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-24
        • 1970-01-01
        • 1970-01-01
        • 2014-04-11
        相关资源
        最近更新 更多