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

a=(a+;+;)*(a+;+;)在Java中给出了奇怪的结果,java,post-increment,operator-precedence,ocpjp,Java,Post Increment,Operator Precedence,Ocpjp,我正在准备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); 你的声明: a += (a++) * (a++

我正在准备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);
你的声明:

a += (a++) * (a++);
等同于以下任何一项:

a = a*a + 2*a
a = a*(a+2)
a += a*(a+1)
在第一个
a++
a
变为4之后,使用其中任何一个。所以你有
3*4=12

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

(a++)
是后增量,所以表达式的值是3

(a++)
是后增量,所以表达式的值现在是4

表达式求值是从左到右进行的

3 * 4 = 12 

每次使用a++时,您都在后加a。这意味着第一个a++计算为3,第二个计算为4。3*4=12。

如果下次使用a++时使用a++,它将递增1。那你干什么呢

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

a++
表示“a的值,然后a加1”。所以当你跑步的时候

(a++) * (a++)
首先计算第一个
a++
,并生成值3<代码>a然后递增1。然后计算第二个
a++
a
生成4的值,然后再次递增(但现在这无关紧要)

所以这变成了

a = 3 * 4
它等于12。

(a++)
表示返回
a
和增量,所以
(a++)*(a++)
表示3*4

是12。 表达式从左开始计算。它确实:

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

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

对运算符的工作原理普遍缺乏了解。老实说,每个操作符都是语法糖

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

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)
然后可以使用这些泛化重写复合运算符(为了简单起见,请忽略返回类型):

您可以重写您的示例:

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

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

Operators.set(a, 3)
Operators.set(b, Operators.postIncrement(a))
Operators.set(c, Operators.postIncrement(a))
Operators.set(a, Operators.multiply(b, c))
这样做肯定会更加冗长,但很明显,您永远不希望在一行上执行两个以上的操作

int a = 3;
a += (a++) * (a++);
首先构建语法树:

+=
  a
  *
    a++
    a++
要计算它,请从最外层的元素开始,然后递归下降。对于每个元素,请执行以下操作:

  • 从左到右评估儿童
  • 评估元素本身
+=
运算符很特殊:它被扩展为类似于
left=left+right
,但只对表达式
left
求值一次。但是,在右侧求值为值之前,左侧求值为值(而不仅仅是变量)

这导致:

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

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

    示例1

    int a = 3;
    
    a = (++a) * (a++);
    
    System.out.println(a); // 16
    
    示例2

    int a = 3;
    
    a = (++a) * (++a);
    
    System.out.println(a); // 20
    
    只需确保将根据位置更改值的
    ++
    表达式放在何处。

    以下是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)

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

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

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

    因此,它最终从堆栈(4和3)中弹出第一个两个值,将其相乘并存储回堆栈(12)

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

    最后是堆栈中的pops 12,存储在a

     11  istore_1 [a]
    

    塔达

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

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

    17

    在以下情况下:

    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 
    
    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
    
    因此,我们得到的输出为12。 在下列情况下:

    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 
    
    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
    

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

    任何人都不应该编写这样的代码。相信编译器——它比你更了解Java。我想是科雷
     11  istore_1 [a]
    
    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 
    
    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