i++和++i探秘

从最开始接触编程,就一直有人告诉我们i++和++i不一样,但是没有告诉我,为什么会不一样。呵呵~~

今天来了解下为什么会不一样。

 

首先,来认识一下本文的核心工具:javap命令

javap是jdk自带的一个工具,可以反编译,也可以查看java编译器生成的字节码,是分析代码的一个好工具。

通过它,我们可以对照源代码和字节码,从而了解很多编译器内部的工作。

javap命令格式:

javap [ options ] class

options 选项:

-l                 输出行和变量的表
-public         只输出public方法和域
-protected     只输出publicprotected类和成员
-package     只输出包,publicprotected类和成员,这是默认的
-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 }
复制代码

 

 

 

 

posted @   yejg1212  阅读(382)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端
点击右上角即可分享
微信分享提示