对于两个代码片段,数组分配输出的行为有所不同

时间:2014-10-11 07:15:03

标签: java arrays variable-assignment

第一个代码段打印2

public static void main(String args[]) throws Exception {  
    int[] a = { 1, 2, 3, 4 };
    int[] b = { 2, 3, 1, 0 };
    int val = (a = b)[3];
    System.out.println( a [val  ] );
}

第二个代码段输出1

public static void main(String args[]) throws Exception {
    int[] a = { 1, 2, 3, 4 };
    int[] b = { 2, 3, 1, 0 };
    int val;
    System.out.println(a[val = ((a = b)[3])]);
}

发生了什么事?

output1

2nd output

6 个答案:

答案 0 :(得分:2)

输出合理。让我们将两个复杂的行扩展为几个单独的语句。第一个片段:

// This...
int val = (a = b)[3];
// Becomes...
a = b;
int val = a[3]; // 0

因此打印a[val]将打印a[0],现在为2。

第二个片段更复杂。棘手的是"我们正在将数据索引到" 之前评估剩余的副作用。所以:

// This...
System.out.println(a[val = ((a = b)[3])]);
// Becomes...
int[] tmp = a; // So tmp is { 1, 2, 3, 4 }
a = b;
val = a[3]; // 0
System.out.println(tmp[val]); // 1

JLS section 15.10.4详细介绍了这一点。这里的重要部分是:

  

在运行时,对数组访问表达式的评估表现如下:

     
      
  • 首先,评估数组引用表达式。如果评估突然完成评估。
  •   
  • 否则,将评估索引表达式。如果此评估突然完成[...]
  •   
  • 否则,如果数组引用表达式的值为null [...]
  •   
  • 否则,数组引用表达式的值确实是指数组。如果索引表达式的值小于零[...]
  •   
  • 否则,数组访问的结果是数组中类型T的变量,由索引表达式的值选择。
  •   

答案 1 :(得分:1)

在第一个代码片段中,有趣的部分是

int val = (a = b)[3]

这里有两个作业。第一个(a = b)将首先发生,并让变量a也引用b引用的数组(请注意,旧数组不再被引用,因此有资格成为垃圾收集)。

然后你要求索引3上的元素。那就是值“0”。然后输出请求该数组中索引0上的元素。正如您所看到的,这是值“2”。请注意,a现在引用与b相同的数组。

在第二个代码段中,您在同一行中执行所有操作:

System.out.println(a[val = ((a = b)[3])]);

虽然赋值和索引看起来相同,但这里的主要区别在于您在重新分配变量之前访问数组(由a引用)

因此,在完成所有分配后,变量val具有相同的值“0”,变量a引用与b相同的数组。但是现在将查找旧数组中的第一个元素(索引0)。这就是“1”。

答案 2 :(得分:1)

Java语言规范的相关部分(15.13.1。阵列访问的运行时评估)指出:

  

使用以下过程评估数组访问表达式:   首先,评估数组引用表达式。如果此评估突然完成,则阵列访问完成   突然出于同样的原因而且索引表达式没有   评估。   否则,将评估索引表达式。如果此评估突然完成,则阵列访问会因同样的原因突然完成。

第一个片段是简单的部分:在语句int val = (a = b)[3];之后,数组变量a指向数组{ 2, 3, 1, 0 },将索引为0的元素给出答案2.

在第二个片段中,a在索引表达式之前进行求值,因此a指向数组{ 1, 2, 3, 4 }。将索引为0的元素给出答案1。

答案 3 :(得分:1)

第一

int[] a = { 1, 2, 3, 4 };
int[] b = { 2, 3, 1, 0 };

int val = (a = b)[3];
/**
* a=b => a = { 2, 3, 1, 0 };
* val = a[3] = 0;
* a[val] => a[0] =>2;
**/

System.out.println( a [val  ] );  //2

第二

int[] a = { 1, 2, 3, 4 };
int[] b = { 2, 3, 1, 0 };
int val;
System.out.println(a[val = ((a = b)[3])]);
/**
* a[val = ((a = b)[3])]    
* => a[val=(b[3])]   val is not used here
* => a[b[3]] => a[0] => 1
**/

答案 4 :(得分:0)

有两套表现:

1. int val = (a = b)[3];
2. a [val]

B

1. a[val = ((a = b)[3])]

执行 A.1 a={2,3,1,0}val=0以后a[val]=2

执行 B.1 a={1,2,3,4}val=0a[val]=1

B 中,(a=b)是对{2,3,1,0}的引用,因此(a=b)[3]=0val=0以及a是对{1,2,3,4}的引用(因为作业尚未完成),所以a[0]=1

答案 5 :(得分:0)

所以在第一个例子中,b被赋值为a,val等于b,0的第4个值,然后我们用索引0,2打印该值。你得到了这个。

在第二个示例中,由于所有操作都是一次完成的,因此在访问索引0时仍然保持其初始值,因此打印1。第二个片段相当于:

int val = b[3];
System.out.println(a[val]);
a =b;