Do you really understand i + + and + + i? Understand it in bytecode!

Keywords: Java

i++

When we first learned i + + and + + i, we always kept in mind that i + + was used first and then added with 1, + + i was used first and then added with 1. We have been carrying bricks like this for a long time (this conclusion is no problem of course), so have i. Until i see the following question.

public static void func(){
    int i=0;
    for(int j=0;j < 100;j++){
        i = i++;
    }
    Stystem.out.println(i);//Print what???
}

I think it's printed 100, no doubt, I'm wrong. By the way, there is no such article.
It seems that I'm still too busy. Look at the bytecode!

 0 iconst_0
 1 istore_0
 2 iconst_0
 3 istore_1
 4 iload_1
 5 bipush 100
 7 if_icmpge 21 (+14)

10 iload_0
11 iinc 0,1
14 istore_0

15 iinc 1,1
18 goto 4 (-14)
21 getstatic #2 <java/lang/System.out>
24 iload_0
25 invokevirtual #3 <java/io/PrintStream.println>
28 return

Among them, 10-14 corresponds to the bytecode of i=i + +. It is strongly recommended to install the Jclasslib plug-in for IDEA, so that it is more convenient to specify the meaning of mnemonics.

  • iload_0: push the value of the local variable with index 0 of the local variable array of the current stack frame to the operand stack.
  • iinc 0,1: increments the local variable with index 0 by 1.
  • istore_0: pops the value from the operand stack (recorded as val) and sets the local variable value with index 0 to val.

After reading these three mnemonics, we will find that although the value of iinc is increasing, it is not set to i, so the value of i has not changed, and i + + has no effect at all. The dynamic diagram is as follows:

Well, that's it. i was changed and then overridden by the stack value_

++i

Now let's change the question to + + i.

public static void func(){
    int i=0;
    for(int j=0;j < 100;j++){
        i = ++i;
    }
    Stystem.out.println(i);//Print what???
}

The corresponding bytecode is as follows.

 0 iconst_0
 1 istore_0
 2 iconst_0
 3 istore_1
 4 iload_1
 5 bipush 100
 7 if_icmpge 21 (+14)

10 iinc 0,1
13 iload_0
14 istore_0

15 iinc 1,1
18 goto 4 (-14)
21 getstatic #2 <java/lang/System.out>
24 iload_0
25 invokevirtual #3 <java/io/PrintStream.println>

It's still the same 10-14 lines,

So i can be changed, print 100.

Hybrid operation

In the written test questions of i + + and + + i, they are often mixed, a pile of + headache. For example: i = (i + + + (i + + + + + + + i) + (+ + i);. Let's start with a simple one (i = i + + + + + + i;), otherwise the bytecode will be confused. In fact, the answer is very simple, but we need to understand it better through its bytecode. The bytecode is as follows.

 0 iconst_0
 1 istore_0

 2 iload_0
 3 iinc 0,1
 6 iinc 0,1
 9 iload_0
10 iadd
11 istore_0

12 getstatic #2 <java/lang/System.out>
15 iload_0
16 invokevirtual #3 <java/io/PrintStream.println>
19 return

We only need to focus on lines 2-11. The values and stacks corresponding to these steps are shown in the figure below. This is also the purpose of this paper. Let's learn a mnemonic first.

iadd
Both value1 and value2 must be of type int. The values are popped from the operand stack. The int result is value1 + value2. The result is pushed onto the operand stack.
 
The result is the 32 low-order bits of the true mathematical result in a sufficiently wide two's complement format, represented as a value of type int. If overflow occurs, then the sign of the result may not be the same as the sign of the mathematical sum of the two values.
 
Despite the fact that overflow may occur, execution of an iadd instruction never throws a run-time exception.
 
Well, iadd After adding, the value will be pushed into the stack, remember!!






Difficult mode

Let's draw it I = (I + + + (I + + + + + + I) + + + I); see if the examiner can draw the process map. The bytecode is as follows.

 0 iconst_0
 1 istore_0

 2 iload_0
 3 iinc 0,1
 6 iload_0
 7 iinc 0,1
10 iadd
11 iinc 0,1
14 iload_0
15 iadd
16 iinc 0,1
19 iload_0
20 iadd
21 istore_0

22 getstatic #2 <java/lang/System.out>
25 iload_0
26 invokevirtual #3 <java/io/PrintStream.println>
29 return

We just need to focus on lines 2-21.

Posted by ded on Sun, 17 May 2020 20:25:02 -0700