数组引用表达式未完全评估

时间:2012-08-22 04:53:33

标签: java arrays post-increment

你们是否会在以下方面给我启发:

摘录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在第二个代码块中没有增加两次?

我错过了什么?

感谢。

2 个答案:

答案 0 :(得分:2)

我相信它会发生如下:

  1. 程序运行到getArray():返回null。
  2. 然后程序移动到方括号,计算参数,然后尝试进入数组。 (我不熟悉的Java魔法发生在这里)
  3. 尝试失败,并且在第二个索引运算符被查看之前生成之外的异常。
  4. 如果我们想以另一种方式放置你的第二个片段,它应该等同于以下内容(因此产生与第一个片段相同的结果):

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

答案 1 :(得分:1)

my comment中所述......

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


这符合§15.13 of the Java Language Specification,它描述了数组访问表达式。

ArrayAccess:
    ExpressionName [ Expression ]
    PrimaryNoNewArray [ Expression ]

表达式评估的逐步程序在§15.13.1 Run-time Evaluation of Array Access中明确说明:

  

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

     
      
  • 首先,计算数组引用表达式。如果此评估突然完成,则数组访问会因同样的原因而突然完成,并且不会评估索引表达式。

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

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

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

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

         
  •   

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

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

遵循评估规则,为了评估表达式getArray()[i++][i++],我们首先必须评估数组引用表达式,即getArray()[i++]。事实证明,这本身就是一个数组访问和表达式,我们必须应用相同的规则。评估getArray()会产生null。索引表达式i++也完全完成(递增i),然后到达此时抛出NullPointerException的步骤。由于外部数组访问表达式的数组引用表达式突然结束,因此也不会评估外部访问表达式的索引表达式(i++),这意味着i仅递增一次。

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