a = (a++) * (a++) 在 Java 中给出奇怪的结果

发布于 2024-12-14 06:28:57 字数 334 浏览 0 评论 0原文

我正在准备 OCPJP 考试,因此我必须了解 Java 的每一个奇怪的细节。这包括前置和后置增量运算符应用于变量的顺序。下面的代码给了我奇怪的结果:

int a = 3;

a = (a++) * (a++);

System.out.println(a); // 12

答案不应该是 11 吗?或者也许13?但不是12!

后续:

以下代码的结果是什么?

int a = 3;

a += (a++) * (a++);

System.out.println(a);

I'm studying for the OCPJP exam, and so I have to understand every little strange detail of Java. This includes the order in which the pre- and post-increment operators apply to variables. The following code is giving me strange results:

int a = 3;

a = (a++) * (a++);

System.out.println(a); // 12

Shouldn't the answer be 11? Or maybe 13? But not 12!

FOLLOW UP:

What is the result of the following code?

int a = 3;

a += (a++) * (a++);

System.out.println(a);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

静若繁花 2024-12-21 06:28:57

之后第一个a++a变成4。所以你有3 * 4 = 12

a 在第二个 a++ 之后变为 5,但它被丢弃,因为赋值 a = 会覆盖它)

After the first a++ a becomes 4. So you have 3 * 4 = 12.

(a becomes 5 after the 2nd a++, but that is discarded, because the assignment a = overrides it)

廻憶裏菂餘溫 2024-12-21 06:28:57

您的陈述:

a += (a++) * (a++);

只是简写

a = a + (a++) * (a++);

并等同于任何这些更简单的表达式:

a = a*a + 2*a
a = a*(a+2)
a += a*(a+1)

使用其中任何一个来代替。

Your statement:

a += (a++) * (a++);

is just a shorthand for

a = a + (a++) * (a++);

and is equivalent to any of those simpler epressions:

a = a*a + 2*a
a = a*(a+2)
a += a*(a+1)

Use any of those instead.

你曾走过我的故事 2024-12-21 06:28:57

a++ 表示“a 的值,然后 a 加 1”。因此,当您运行

(a++) * (a++)

第一个 a++ 时,首先对其求值,并生成值 3。然后 a 递增 1。然后是第二个 a++评价。 a 产生值 4,然后再次递增(但这现在不重要了)

所以这变成了

a = 3 * 4

等于 12。

a++ means 'the value of a, and a is then incremented by 1'. So when you run

(a++) * (a++)

the first a++ is evaluated first, and produces the value 3. a is then incremented by 1. The second a++ is then evaluated. a produces the value of 4, and is then incremented again (but this doesn't matter now)

So this turns into

a = 3 * 4

which equals 12.

罪#恶を代价 2024-12-21 06:28:57
int a = 3;
a += (a++) * (a++);

首先构建语法树:

+=
  a
  *
    a++
    a++

从最外层元素开始并递归下降来评估它。对于每个元素,请执行以下操作:

  • 从左到右评估子元素
  • 评估元素本身

+= 运算符很特殊:它会扩展为类似 left = left + right,但仅计算表达式 left 一次。在右侧被评估为一个值之前,左侧仍然被评估为一个值(而不仅仅是一个变量)。

这会导致:

  1. 开始计算 +=
  2. 计算变量 a 赋值的左侧。
  3. 将变量 a 计算为将在加法中使用的值 3
  4. 开始评估*
  5. 评估第一个a++。这将返回 3 的当前值并将 a 设置为 4
  6. 计算第二个 a++。这将返回 4 的当前值并将 a 设置为 5
  7. 计算乘积:3*4 = 12
  8. 执行 +=< /代码>。左侧在第三步中被评估为 3,右侧为 12。因此它将 3+12=15 分配给 a
  9. a 的最终值为 15。

这里需要注意的一件事是运算符优先级对计算顺序没有直接影响。它仅影响树的形式,从而间接影响顺序。但在树中的同级中,无论运算符优先级如何,求值始终是从左到右。

int a = 3;
a += (a++) * (a++);

First build the syntax tree:

+=
  a
  *
    a++
    a++

To evaluate it start with the outer most element and descent recursively. For each element do:

  • Evaluate children from left to right
  • Evaluate the element itself

The += operator is special: It gets expanded to something like left = left + right, but only evaluating the expression left once. Still the left side gets evaluated to a value(and not just a variable) before the right side gets evaluated to a value.

This leads to:

  1. Start evaluating +=
  2. Evaluate left side of assignment to the variable a.
  3. Evaluate the variable a to the value 3 which will be used in the addition.
  4. Start evaluating *
  5. Evaluate the first a++. This returns the current value of a 3 and sets a to 4
  6. Evaluate the second a++. This returns the current value of a 4 and sets a to 5
  7. Calculate the product: 3*4 = 12
  8. Execute +=. The left side had been evaluated to 3 in the third step and the right side is 12. So it assigns 3+12=15 to a.
  9. Final value of a is 15.

One thing to note here is that operator precedence has no direct influence on evaluation order. It only affects the form of the tree, and thus indirectly the order. But among siblings in the tree the evaluation is always left-to right, regardless of operator precedence.

寄离 2024-12-21 06:28:57

(a++) 是后增量,因此表达式的值为 3。

(a++) 是后增量,因此表达式的值现在为 4。

表达式计算从左侧开始向右。

3 * 4 = 12 

(a++) is a post increment, so value of expression is 3.

(a++) is post increment, so value of expression is now 4.

Expression evaluation is happening from left to right.

3 * 4 = 12 
隔纱相望 2024-12-21 06:28:57

每次使用 a++ 时,都会对 a 进行后递增。这意味着第一个 a++ 的计算结果为 3,第二个 a++ 的计算结果为 4。3 * 4 = 12。

Each time the you use a++, you're post-incrementing a. That means the first a++ evaluates to 3 and the second evaluates to 4. 3 * 4 = 12.

总攻大人 2024-12-21 06:28:57

人们普遍缺乏对操作员如何工作的了解。老实说,每个运算符都是语法糖。

您所要做的就是了解每个操作员背后实际发生的事情。假设如下:

a = b -> Operators.set(a, b) //don't forget this returns b
a + b -> Operators.add(a, b)
a - b -> Operators.subtract(a, b)
a * b -> Operators.multiply(a, b)
a / b -> Operators.divide(a, b)

然后可以使用这些概括重写复合运算符(为了简单起见,请忽略返回类型):

Operators.addTo(a, b) { //a += b
  return Operators.set(a, Operators.add(a, b));
}

Operators.preIncrement(a) { //++a
  return Operators.addTo(a, 1);
}

Operators.postIncrement(a) { //a++
  Operators.set(b, a);
  Operators.addTo(a, 1);
  return b;
}

您可以重写示例:

int a = 3;
a = (a++) * (a++);

as

Operators.set(a, 3)
Operators.set(a, Operators.multiply(Operators.postIncrement(a), Operators.postIncrement(a)));

可以使用多个变量进行拆分:

Operators.set(a, 3)
Operators.set(b, Operators.postIncrement(a))
Operators.set(c, Operators.postIncrement(a))
Operators.set(a, Operators.multiply(b, c))

这样肯定更冗长,但是很明显,您永远不想在一行上执行两个以上的操作。

There is a general lack of understanding about how operators work. Honestly, every operator is syntactic sugar.

All you have to do is understand what is actually happening behind every operator. Assume the following:

a = b -> Operators.set(a, b) //don't forget this returns b
a + b -> Operators.add(a, b)
a - b -> Operators.subtract(a, b)
a * b -> Operators.multiply(a, b)
a / b -> Operators.divide(a, b)

Compound operators can then be rewritten using these generalizations (please ignore the return types for the sake of simplicity):

Operators.addTo(a, b) { //a += b
  return Operators.set(a, Operators.add(a, b));
}

Operators.preIncrement(a) { //++a
  return Operators.addTo(a, 1);
}

Operators.postIncrement(a) { //a++
  Operators.set(b, a);
  Operators.addTo(a, 1);
  return b;
}

You can rewrite your example:

int a = 3;
a = (a++) * (a++);

as

Operators.set(a, 3)
Operators.set(a, Operators.multiply(Operators.postIncrement(a), Operators.postIncrement(a)));

Which can be split out using multiple variables:

Operators.set(a, 3)
Operators.set(b, Operators.postIncrement(a))
Operators.set(c, Operators.postIncrement(a))
Operators.set(a, Operators.multiply(b, c))

It's certainly more verbose that way, but it immediately becomes apparent that you never want to perform more than two operations on a single line.

峩卟喜欢 2024-12-21 06:28:57

如果是:,

int a = 3;  
a = (a++) * (a++); 

a = 3 * a++; now a is 4 because of post increment
a = 3 * 4; now a is 5 because of second post increment
a = 12; value of 5 is overwritten with 3*4 i.e. 12 

则我们得到的输出为 12。

如果是:,

a += (a++) * (a++); 
a = a + (a++) * (a++);
a = 3 + (a++) * (a++); // a is 3
a = 3 + 3 * (a++); //a is 4
a = 3 + 3 * 4; //a is 5
a = 15

这里要注意的要点是,在这种情况下,编译器从左到右求解,并且
在后增量的情况下,在计算中使用增量之前的值,并且当我们从左向右移动时,使用增量值。

In case of :

int a = 3;  
a = (a++) * (a++); 

a = 3 * a++; now a is 4 because of post increment
a = 3 * 4; now a is 5 because of second post increment
a = 12; value of 5 is overwritten with 3*4 i.e. 12 

hence we get output as 12.

In case of :

a += (a++) * (a++); 
a = a + (a++) * (a++);
a = 3 + (a++) * (a++); // a is 3
a = 3 + 3 * (a++); //a is 4
a = 3 + 3 * 4; //a is 5
a = 15

Main point to note here is that in this case compiler is solving from left to right and
in case of post increment, value before increment is used in calculation and as we move from left to right incremented value is used.

旧梦荧光笔 2024-12-21 06:28:57

(a++) 表示返回 a 并递增,所以
(a++) * (a++) 表示 3 * 4

(a++) means return a and increment, so
(a++) * (a++) means 3 * 4

一生独一 2024-12-21 06:28:57

这是 java 代码:

int a = 3;
a = (a++)*(a++);

这是字节码:

  0  iconst_3
  1  istore_1 [a]
  2  iload_1 [a]
  3  iinc 1 1 [a]
  6  iload_1 [a]
  7  iinc 1 1 [a]
 10  imul
 11  istore_1 [a]

这是发生的情况:

将 3 压入堆栈,然后从堆栈中弹出 3 并将其存储在 a 中。
现在 a = 3 并且堆栈为空。

  0  iconst_3
  1  istore_1 a

现在,它将“a”(3) 中的值推入堆栈,然后递增 a(3 -> 4)。

  2  iload_1 [a]
  3  iinc 1 1 [a]

所以现在“a”等于“4”,堆栈等于{3}。

然后它再次加载“a”(4),推入堆栈并递增“a”。

  6  iload_1 [a]
  7  iinc 1 1 [a]

现在“a”等于 5,堆栈等于 {4,3}

所以它最终从堆栈中弹出前两个值(4 和 3),相乘并将其存储回堆栈(12)。

 10  imul

现在“a”等于 5,堆栈等于 12。

最后从堆栈中弹出 12 并存储在 a 处。

 11  istore_1 [a]

田田!

Here is the java code:

int a = 3;
a = (a++)*(a++);

Here is the bytecode:

  0  iconst_3
  1  istore_1 [a]
  2  iload_1 [a]
  3  iinc 1 1 [a]
  6  iload_1 [a]
  7  iinc 1 1 [a]
 10  imul
 11  istore_1 [a]

Here is what happens:

Pushes 3 into the stack then pops 3 from the stack and stores it at a.
Now a = 3 and the stack is empty.

  0  iconst_3
  1  istore_1 a

Now it pushes the value from "a" (3) into the stack, and then increments a(3 -> 4).

  2  iload_1 [a]
  3  iinc 1 1 [a]

So now "a" equals "4" the stack equals {3}.

Then it loads "a" again (4), pushes into the stack and increments "a".

  6  iload_1 [a]
  7  iinc 1 1 [a]

Now "a" equals 5 and the stack equals {4,3}

So it finally pops the fisrt two values from the stack (4 and 3), multiplies and stores it back into the stack (12).

 10  imul

Now "a" equals 5 and the stack equals 12.

Finally is pops 12 from the stack and stores at a.

 11  istore_1 [a]

TADA!

浮云落日 2024-12-21 06:28:57

现在是 12 点。
表达式从左侧开始计算。确实如此:

a = (3++) * (4++);

计算第一部分 (3++) 后,a 为 4,因此在下一部分中,a = 3*4 = 12。
请注意,最后一个后递增 (4++) 被执行,但没有任何效果,因为在此之后为 a 分配了值 12。

It is 12.
The expression starts evaluating from left. So it does:

a = (3++) * (4++);

Once the first part (3++) is evaluated, a is 4, so in the next part, it does a = 3*4 = 12.
Note that the last post-increment (4++) is executed but has no effect since a is assigned with the value 12 after this.

抚笙 2024-12-21 06:28:57

示例 1

int a = 3;

a = (++a) * (a++);

System.out.println(a); // 16

示例 2

int a = 3;

a = (++a) * (++a);

System.out.println(a); // 20

只是为了确定在哪里放置 ++ 表达式,该表达式会根据位置更改值。

Example 1

int a = 3;

a = (++a) * (a++);

System.out.println(a); // 16

Example 2

int a = 3;

a = (++a) * (++a);

System.out.println(a); // 20

Just to make sure where to put ++ expression which changes the value based on the location.

花开半夏魅人心 2024-12-21 06:28:57

每个人都清楚地解释了第一个表达式,以及为什么 a 的值为 12。

对于接下来的问题,答案对于不经意的观察者来说是完全显而易见的:

17

Everyone has clearly explained the first expression, and why the value of a is 12.

For the follow on question, the answer is totally obvious to the casual observer:

17

毁虫ゝ 2024-12-21 06:28:57

前&前缀后增量的优先级高于乘法运算符。因此表达式的计算结果为 3*4。

Pre & post-prefix increments have a higher precedence than the multiplication operator. hence the expression is evaluated as 3*4.

落日海湾 2024-12-21 06:28:57

如果您使用 a++ ,则下次使用 a 时,它会增加 1。所以你的所作所为

a = 3 * (3 + 1) = 3 * 4 = 12

If you use a++ the next time you use a it is incremented by one. So your doing

a = 3 * (3 + 1) = 3 * 4 = 12
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文