之前一篇 i++与i--的分析 ,说明了在执行i++或i--操作时,应运用所学的计算机知识:数据操作的原理,应理解清楚操作数和栈的关系。当时也没整理清楚。最近又遇到i++和i--相关的题。又把自己给整懵了。在看了解析class反编译文件 后,也去分析class文件,最终算是真正弄明白了i++和i--。
在要理解i++和i--的原理之前,需要明白java的栈和堆方面的知识。这里就不再介绍栈和堆了。下面主要贴图说明i++的实现原理。只要分析清楚了i++,i--就不在话下。
下面看java源程序:
package com.michael.test;
/**
* @author michael
* @email wqjsir@foxmail.com
* @version 1.0
*/
public class TestMain {
public static void main(String[] args){
int i = 0 ;
i = i++ + ++i;
System.err.println(i);
}
}
在dos下先编译该文件javac TestMain.java
再执行javap -verbose TestMain输出如下
Compiled from "TestMain.java"
public class com.michael.test.TestMain extends java.lang.Object
SourceFile: "TestMain.java"
minor version: 0
major version: 50
Constant pool:
const #1 = Method #5.#14; // java/lang/Object."<init>":()V
const #2 = Field #15.#16; // java/lang/System.err:Ljava/io/PrintStre
const #3 = Method #17.#18; // java/io/PrintStream.println:(I)V
const #4 = class #19; // com/michael/test/TestMain
const #5 = class #20; // java/lang/Object
const #6 = Asciz <init>;
const #7 = Asciz ()V;
const #8 = Asciz Code;
const #9 = Asciz LineNumberTable;
const #10 = Asciz main;
const #11 = Asciz ([Ljava/lang/String;)V;
const #12 = Asciz SourceFile;
const #13 = Asciz TestMain.java;
const #14 = NameAndType #6:#7;// "<init>":()V
const #15 = class #21; // java/lang/System
const #16 = NameAndType #22:#23;// err:Ljava/io/PrintStream;
const #17 = class #24; // java/io/PrintStream
const #18 = NameAndType #25:#26;// println:(I)V
const #19 = Asciz com/michael/test/TestMain;
const #20 = Asciz java/lang/Object;
const #21 = Asciz java/lang/System;
const #22 = Asciz err;
const #23 = Asciz Ljava/io/PrintStream;;
const #24 = Asciz java/io/PrintStream;
const #25 = Asciz println;
const #26 = Asciz (I)V;
{
public com.michael.test.TestMain();
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 8: 0
public static void main(java.lang.String[]);
Code:
Stack=2, Locals=2, Args_size=1
0: iconst_0
1: istore_1
2: iload_1
3: iinc 1, 1
6: iinc 1, 1
9: iload_1
10: iadd
11: istore_1
12: getstatic #2; //Field java/lang/System.err:Ljava/io/PrintStream;
15: iload_1
16: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
19: return
LineNumberTable:
line 11: 0
line 12: 2
line 13: 12
line 14: 19
}
这里主要分析对数据操作部分。其他部分可参考前一篇 解析class反编译文件
下面贴图说明数据的操作过程:
经过上面的分析,可以知道在对数据执行基本运算时都是对操作数栈中的数据进行操作。而对保存在堆中的变量本身没有影响。
看下面的代码:
代码一:
public class TestMain {
public static void main(String[] args){
int i = 0 ;
i = ++i + i++ ;
System.err.println(i);
}
}
代码二:
public class TestMain {
public static void main(String[] args){
int i = 0 ;
i = i++ + ++i;
System.err.println(i);
}
}
代码一二的输出结果都为2。通过上面的分析就能理解为什么等于2了。