第一个代码段打印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])]);
}
发生了什么事?
答案 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=0
时a[val]=1
在 B
中,(a=b)
是对{2,3,1,0}
的引用,因此(a=b)[3]=0
和val=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;