从最开始接触编程,就一直有人告诉我们i++和++i不一样,但是没有告诉我,为什么会不一样。呵呵~~
今天来了解下为什么会不一样。
首先,来认识一下本文的核心工具:javap命令
javap是jdk自带的一个工具,可以反编译,也可以查看java编译器生成的字节码,是分析代码的一个好工具。
通过它,我们可以对照源代码和字节码,从而了解很多编译器内部的工作。
javap命令格式:
javap [ options ] class
options 选项:
-l 输出行和变量的表 -public 只输出public方法和域 -protected 只输出public和protected类和成员 -package 只输出包,public和protected类和成员,这是默认的 -private 输出所有类和成员 -s 输出内部类型签名 -c 输出分解后的代码,例如,类中每一个方法内,包含java字节码的指令, -verbose 输出栈大小,方法参数的个数
ok,回到正题。先写个HelloWord小程序
public class Hello { public static void main(String args[]){ int i=2; i++; int j=1; ++j; } }
将其编译,编译完成之后,执行如下命令:
javac Hello.java
javap -c Hello
得到如下输出:
E:\>javap -c Hello Compiled from "Hello.java" public class Hello extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: iconst_2 //把2放到栈顶 1: istore_1 //把栈顶的值放到局部变量1中,即i中 2: iinc 1, 1 //这个指令,把局部变量1,也就是i,增加1,这个指令不会导致栈的变化,i此时变成3了
5: iconst_1 //把1放到栈顶 6: istore_2 //把栈顶的值放到局部变量2中,即j中 7: iinc 2, 1 //把局部变量2,也就是j的值,增加1,这个指令不会导致栈的变化,j变成2了 10: return }
下面在再来看看这个程序:
public class Hello { public static void main(String args[]){ int i=2; i=i++; int j=1; j=++j; } }
再来看看这个反编译的结果:
E:\>javap -c Hello Compiled from "Hello.java" public class Hello extends java.lang.Object{ public Hello(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: iconst_2 //把2放到栈顶(栈顶=2) 1: istore_1 //把栈顶的值放到局部变量1中,即i中(i=2,栈顶=2) 2: iload_1 //把局部变量1的值,即2放到栈顶,也就是说此时栈顶的值是2(i=2,栈顶=2) 3: iinc 1, 1 //这个指令,把局部变量1,也就是i,增加1,这个指令不会导致栈的变化,i此时变成3了(i=3,栈顶=2) 6: istore_1 //把栈顶的值放到局部变量1中,即i中,栈顶的值是2! (i=2,栈顶=2)
7: iconst_1 //把1放到栈顶(栈顶=1) 8: istore_2 //把栈顶的值放到局部变量2中,即j中(j=1,栈顶=1) 9: iinc 2, 1 //把局部变量2,也就是j,增加1,这个指令不会导致栈的变化,j此时变成2了(j=2,栈顶=1) 12: iload_2 //把局部变量2的值,即2放到栈顶(j=2,栈顶=2) 13: istore_2 //将栈顶值放到局部变量2中,即j中,所以j=2了(j=2,栈顶=2) 14: return }