Java 为什么在包含前缀和后缀的表达式中,前缀的计算要先于后缀?
根据,一种操作,例如:Java 为什么在包含前缀和后缀的表达式中,前缀的计算要先于后缀?,java,operator-precedence,unary-operator,Java,Operator Precedence,Unary Operator,根据,一种操作,例如: x-- // Returns x, then subtracts 1 from x. 应优先于: --x // Subtracts 1 from x, then returns x. 那么,鉴于下面的小片段,为什么: int x = 5; int y = --x * 5 + x--; System.out.println(x+" vs "+y); 打印3对24而不是3对20 精化 假设给定的运算符优先级顺序,可以将代码段的第#2行分解为以下伪块(以前的评估值放在方括
x-- // Returns x, then subtracts 1 from x.
应优先于:
--x // Subtracts 1 from x, then returns x.
那么,鉴于下面的小片段,为什么:
int x = 5;
int y = --x * 5 + x--;
System.out.println(x+" vs "+y);
打印3对24
而不是3对20
精化
假设给定的运算符优先级顺序,可以将代码段的第#2行分解为以下伪块(以前的评估值放在方括号中):
x--
--x
[--x]*5
[--x*5]+[x-->
y=[--x*5+x-->
返回5
将x设置为4
在2之后将x设置为3
返回3
3之后将3乘以5并返回15
4之后将15添加到5,并返回20
5后将y设置为20
为什么返回的值是24而不是20
p.S.
(如果计算x之前的x,则得到24,但由于运算符优先级的原因,情况不应如此)
我是瞎了还是数学不好?x——发生在指令执行之后。
所以它就像是4*5+4;在执行这条语句之后,x再次减少到3
这就是为什么3和24运算符的操作数总是从左到右求值,而不考虑优先级所规定的运算顺序 发生的情况如下:
--x
。将x
设置为4
,生成4
(-x)*5
<此时code>x为4
,因此计算4*5
并生成20
x--
。产生4
,将x
设置为3
((-x)*5)+x--代码>。将20
添加到4
以生成24
“3对24”
操作数从左到右求值,您认为这是从右到左。所以--x被设置为4,然后--x*5,也就是4*5等于20。然后--x*5+x--24。最后x-,计算为3 从Java文档: Java编程语言保证 运算符似乎按特定的求值顺序求值, 即,从左到右
下面是一个关于Java优先级的。因此,Java编译器找到以下表达式:
int x = 5;
int y = --x * 5 + x--;
并且必须决定生成字节码的操作顺序。一行中有四个运算符:-、*、+和-,而没有一个括号,因此优秀的编译器会检查其前序表,并放入您懒惰的程序员忽略的括号:
((--OP1) * OP2) + (OP3--)
请注意,在这个阶段,操作数是不透明的实体:不管它们是变量(意味着从内存读取)、常量、方法调用、隐式取消装箱还是其他什么——括号化过程不需要知道
最后,当发出字节码时,编译器还有另一条规则要遵守:操作数必须从左到右求值,以便从内存读取和写入的操作(例如变量递减/递增和方法调用)具有有保证的顺序。因此,在指令序列中必须:
OP1
...
OP2
...
OP3
让我们使用IntegerVariable
面向对象来查看更直观的示例:
public class IntegerVariable {
private int val;
public IntegerVariable(int val) {
this.val = val;
}
public int getAndDecrement() {
return val--;
}
public int decrementAndGet() {
return --val;
}
public int get() {
return val;
}
public static IntegerVariable Int(int val) {
return new IntegerVariable(val);
}
public static void main(String... args) {
IntegerVariable x = Int(5);
int y = x.decrementAndGet() * Int(5).get() + x.getAndDecrement();
}
}
如果在get()
、decrementAndGet()
和getAndDecrement()
设置断点,则可以清楚地看到
- 计算顺序,通过使用虚拟调用使其可调试。求值顺序为从左到右,并保证在操作发生之前对操作数进行完全求值
- 运算符优先级,它基本上只是放上省略的括号:
y=((-x)*5)+(x-)
4*5+6
可能表示(4*5)+6
或4*(5+6)
。因为*
具有更高的运算符优先级,所以正确的运算符优先
前缀和后缀减量和增量都具有较高的运算符优先级,因此--x*5
表示(-x)*5
,而不是--(x*5)
。显然,后一个表达式将产生编译器错误,因为x*5
不是变量。这就是前缀和后缀减量和增量具有较高运算符优先级的原因:将--x*5
计算为--(x*5)
是没有意义的
因此,在您的例子中,表达式相当于
(-x)*5)+(x-)
。然后可以对该表达式求值,操作数严格从左到右求值。可能重复的@AaronKurtzhals实际上不是该表达式的重复。在这个例子中,OP知道操作员是如何独立工作的;问题是当它们是同一表达式的一部分时,它们的求值顺序。这只是求值顺序,与运算符优先级本身没有太大关系。是否要排除赋值运算符?你分解了示例中的所有其他操作,即使这与这里无关,也可能是因为x也是任务的目标。我不确定你是否误解了正在发生的事情,或者只是没有很好地解释它,而是按照这个answ