5

我只是在检查一些 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的初始化默认值是否有所不同?

4

3 回答 3

5

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

String[][] a

当你写

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

您初始化外部数组,但不创建内部数组,a[0]因此null.

当你写

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

运行时还创建内部数组。它在规范中描述:

在运行时,数组创建表达式的评估行为如下:

如果没有维度表达式,则必须有一个数组初始值设定项。

新分配的数组将使用数组初始化器提供的值进行初始化,如 §10.6 中所述。

数组初始值设定项的值成为数组创建表达式的值。

否则,没有数组初始值设定项,并且:

首先,从左到右评估维度表达式。如果任何表达式计算突然完成,则不会计算其右侧的表达式。

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

接下来,为新数组分配空间。如果没有足够的空间来分配数组,则数组创建表达式的计算会通过抛出 OutOfMemoryError 突然完成。

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

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

多维数组不需要在每一层都有相同长度的数组。

于 2013-05-26T18:05:29.387 回答
1
String[][] a = new String[3][];

相当于:

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

并且a[0][0]类似于a1[0]throws NPE。


您在这里有两个选择:

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

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

于 2013-05-26T18:05:41.000 回答
1

好发现。当您使用两个参数初始化二维数组时,会发生以下情况:

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!

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

在此处输入图像描述

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

于 2013-05-26T18:25:33.003 回答