A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

直接看下面的两段代码:
[Java] 纯文本查看 复制代码
public static void main(String[] args) {
		int i = 1;
		i = i++;
		System.out.println("i=" + i);
	}

输出结果:
[Java] 纯文本查看 复制代码
i=1


[Java] 纯文本查看 复制代码
public static void main(String[] args) {
		int i = 1;
		int b = 0;
		b = i++;
		System.out.println("i=" + i);
	}

输出结果:
[Java] 纯文本查看 复制代码
i=2



为什么会出现这种问题呢?
我们需要分析下他的代码。我说的代码并不是java代码,而是在jvm中运行的代码也就是class文件。但是我们无法阅读class文件,就需要用java的一个命令来反编译
这个命令就是 javap -c
编译完成后我们查看代码:
[AppleScript] 纯文本查看 复制代码
  public static void main(java.lang.String[]);
    Code:
       0: iconst_1                          //常量1入栈
       1: istore_1                          //将栈顶出栈,即i=1;
       2: iload_1                           //复制i变量的值入栈
       3: iinc          1, 1                //局部变量的值+1
       6: istore_1                          //将栈顶出栈,即i=1;
       7: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      10: new           #3                  // class java/lang/StringBuilder
      13: dup
      14: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      17: ldc           #5                  // String i=
      19: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: iload_1                           //复制i变量的值入栈 这时i=1???还是2????
      23: invokevirtual #7                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      26: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      29: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      32: return
}

看完这个我们就需要大概了解下代码里出现的命令了。
iconst_n :定义常量0,在字节码里,-1~5可以表示为iconst_n形式,也就是用常量来表示,不在这个范围的数,则要用bipush n或sipush n来表示,也就是将数存入栈中
istore_n :指令可以从栈顶取一个整形数据存储在局部变量区中,n代表在局部变量区中的位置,只能取0,1,2,3,其它的数,则要用istore指令
这两个比较常见
下面附一张表格
Bytecode

Stack

before->after

Description

iconst_0

->0

Loads the int value 0 onto the stack

istore_1

value->

Store int value into variable 1

istore_2

value->

Store int value into variable 2

iinc

No change

Increment local variable #index by signed byte const

iload_1

->value

Loads an int value from variable 1

iadd

value 1,value 2->result

Adds 2 ints together


为了搞清楚这个问题 我们一行一行的读下代码
[Java] 纯文本查看 复制代码
java代码:
public static void main(String[] args) {
            int i = 1;
            i = i++;
            System.out.println("i=" + i);
      }

class反编译代码:
       0: iconst_1                          //常量1入栈
       1: istore_1                          //将栈顶出栈,即i=1;

                                            //前两句的意思就是 i=1 

       2: iload_1                           //复制i变量的值入栈
       3: iinc          1, 1                //局部变量的值+1(注意这里是局部变量的值,栈中的值没有改变还是1)
       6: istore_1                          //将栈顶出栈,即i=1;
                                            //这里其实执行的是i = i++;这句话
                                            //首先把 i的值入栈然后 执行i++ 最后把i入栈的值取出来
                                            //这里我们要注意 入栈时i的值为1 执行i++(即iinc之后 
                                            //栈中的值没有改变,改变的只是变量的值。
                                            //这之后又把栈中的值赋值给变量所以最后i的值还是为1)
       7: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      10: new           #3                  // class java/lang/StringBuilder
      13: dup
      14: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      17: ldc           #5                  // String i=
      19: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: iload_1                           //复制i变量的值入栈 这时i=1 所以最后输出1
      23: invokevirtual #7                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      26: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      29: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      32: return




我们再来分析
[Java] 纯文本查看 复制代码
java代码:
public static void main(String[] args) {
            int i = 1;
            int b = 0;
            b = i++;
            System.out.println("i=" + i);
      }

class反编译代码:

       0: iconst_1                         //常量1入栈
       1: istore_1                         //将栈顶出栈,即i=1;

                                           //前两句的意思就是 i=1 

       2: iconst_0                         //常量0入栈
       3: istore_2                         //将栈顶出栈,即b=0;

                                           //这两句的意思就是 b=0

       4: iload_1                          //复制i变量的值入栈
       5: iinc          1, 1               //局部变量的值+1
       8: istore_2                         //将栈顶出栈,即b=1;

                                            //这里其实执行的是b = i++;这句话
                                            //首先把 i的值入栈然后 执行i++ 最后把i入栈的值取出来
                                            //这里我们要注意 入栈时i的值为1 执行i++(即iinc之后 
                                            //栈中的值没有改变,改变的只是变量的值。
                                            //这之后又把栈中的值赋值给变量b所以最后b的值为1,变量i的值为2)

       9: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      12: new           #3                  // class java/lang/StringBuilder
      15: dup
      16: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      19: ldc           #5                  // String i=
      21: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
      24: iload_1                           //复制i变量的值入栈 i=2
      25: invokevirtual #7                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      28: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      31: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      34: return

至此 我们就可以清楚地知道问题的答案了。

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马