1

各位大侠能否请教我以下几点:

片段1:

public class ArrayKoPo {

    public static int[] getArray() {
        return null;
    }

    public static void main(String args[]) {
        int i = 0;
        try {
            int j = getArray()[i++];
        } catch (Exception e) {
            System.out.println(i); //prints 1 <---- This one I expected.
        }
    }
}

片段 2:

public class ArrayKoPo {

    public static int[][] getArray() {
        return null;
    }

    public static void main(String args[]) {
        int i = 0;
        try {
            int j = getArray()[i++][i++];
        } catch (Exception e) {
            System.out.println(i); //still prints 1 <---- This one I don't understand. I thought 2 will be printed.
        }
    }
}

为什么变量 i 在第二个代码块中没有增加两次?

我错过了什么?

谢谢。

4

2 回答 2

2

我相信它会发生如下情况:

  1. 程序运行到 getArray():返回 null。
  2. 然后程序移动到方括号,评估参数,并尝试进入数组。(我不熟悉的Java魔法发生在这里)
  3. 尝试失败并在查看第二个索引运算符之前生成异常。

如果我们要以另一种方式放置您的第二个片段,它应该等效于以下内容(从而生成与第一个片段相同的结果):

public class ArrayKoPo {

    public static int[][] getArray() {
        return null;
    }

    public static void main(String args[]) {
        int i = 0;
        try {
            int[] j = getArray()[i++];
            int k = j[i++];
        } catch (Exception e) {
            System.out.println(i);
        }
    }
}
于 2012-08-22T05:09:04.243 回答
1

正如我在评论中所说...

首先,重要的是要注意 Java 从左到右计算。我们发现getArray()[i++]尝试访问null被视为数组的元素,从而产生一个NullPointerException. 此异常在评估getArray()[i++][i++]外部数组访问表达式之前中断表达式的评估(其索引计算为i++),因此第二个增量永远不会发生:-)


这符合Java 语言规范的 §15.13,它描述了数组访问表达式。

ArrayAccess:
    ExpressionName [ Expression ]
    PrimaryNoNewArray [ Expression ]

表达式评估的分步过程在§15.13.1 数组访问的运行时评估中明确说明:

使用以下过程评估数组访问表达式:

  • 首先,评估数组引用表达式。如果这个求值突然完成,那么数组访问也会因为同样的原因而突然完成,并且索引表达式不会被求值。

  • 否则,将评估索引表达式。如果此评估突然完成,则阵列访问会出于同样的原因而突然完成。

  • 否则,如果数组引用表达式的值为null,则NullPointerException抛出 a。

  • 否则,数组引用表达式的值确实引用了一个数组。如果索引表达式的值小于零,或者大于或等于数组的length,则ArrayIndexOutOfBoundsException抛出 an。

  • 否则,数组访问的结果是数组中由索引表达式的值选择的类型为 T 的变量。


现在,为了理解我们的结果,您必须意识到 Java 多维数组本质上是锯齿状的,并且实现为数组的数组;anint[][]只是一个数组int[]

手头的真正表达式涉及两个数组访问表达式,即索引表达式为的外部数组访问表达式i++和数组引用表达式本身是数组访问表达式,即引用表达式为getArray()且索引表达式为的数组访问表达式i++

遵循评估规则,要评估表达式getArray()[i++][i++],我们首先必须评估数组引用表达式,即getArray()[i++]。事实证明,这本身就是一个数组访问和表达式,我们必须应用相同的规则。评估getArray()结果null。在到达此时抛出a 的步骤之前,索引表达式i++也完全完成(递增)。由于外部数组访问表达式的数组引用表达式突然结束,所以它也突然结束,因此外部访问表达式的索引表达式 ( ) 不被计算,意思只增加一次。iNullPointerExceptioni++i

...现在你知道了;-)

于 2012-08-22T05:11:01.127 回答