神奇的i++

i++,++i,多简单啊,不需要深入研究吧!!!

我是这样想的。

直到我做了一道Java基础检测题,才发现,哦,原来是这样啊!!!

题是这样的

public class Demo {
public static void main(String args[]) {
int num = 50 ;
num = num ++ * 2 ;
System.out.println(num) ;
}
}
最终的执行结果是什么?

结果是什么?100?102?101?

正确输出是:100

对了就不必往下看了.

Javap介绍

先来看个有用的指令:javap

javap:

javap是jdk自带的反解析工具,通过反编译生成的汇编代码,我们可以深入的了解java代码的工作机制

javap的用法格式:

javap

classes就是你要反编译的class文件

D:\notepadd++cache>javap
用法: javap <options> <classes>
其中, 可能的选项包括:
-help --help -? 输出此用法消息
-version 版本信息
-v -verbose 输出附加信息
-l 输出行号和本地变量表
-public 仅显示公共类和成员
-protected 显示受保护的/公共类和成员
-package 显示程序包/受保护的/公共类
和成员 (默认)
-p -private 显示所有类和成员
-c 对代码进行反汇编
-s 输出内部类型签名
-sysinfo 显示正在处理的类的
系统信息 (路径, 大小, 日期, MD5 散列)
-constants 显示最终常量
-classpath <path> 指定查找用户类文件的位置
-cp <path> 指定查找用户类文件的位置
-bootclasspath <path> 覆盖引导类文件的位置

Jvm指令介绍

这是接下来要用到的Jvm指令的含义,推荐一篇JVM指令博客JVM指令介绍博客

//指令含义

bipush : valuebyte值带符号扩展成int值入栈

istore : 将栈顶int类型值保存到局部变量indexbyte中

iinc : 将指定int型变量增加指定值(i++, i--, i+=2)

iload : 从局部变量indexbyte中装载int类型值入栈

iconst_2: 2(int)值入栈

imul : 将栈顶两int类型数相乘,结果入栈。

分析

通过javap来分析下程序的运行机制

把这段代码放到StrTest.java中

 public class StrTest {
public static void main(String args[]) {
int num1 = 50 ;
num1 = num1++ * 2 ;
System.out.println(num1) ;
}
}

通过cmd执行javac StrTest.java ->javap -c StrTest.class得到如下反汇编代码

public class StrTest {
public StrTest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: bipush 50
2: istore_1
3: iload_1
4: iinc 1, 1
7: iconst_2
8: imul
9: istore_1
10: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
13: iload_1
14: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
17: return
}

把上边的内容添加上注释,瞬间就能明白,为啥结果是100了。

public static void main(java.lang.String[]);
Code:
0: bipush 50 //把50推入栈顶top
2: istore_1 //将50保存到第二个局部变量中->num1=50
3: iload_1 //把局部变量num1的值推入栈顶,此时栈顶值top是50
4: iinc 1, 1 //将50执行加1->50+1 局部变量num1值是51
7: iconst_2 //把2推入栈顶
8: imul //把50和2相乘,并把结果100推入栈顶,此时栈顶值top是100
9: istore_1 //把100保存到第二个局部变量中->num1=100
10: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
13: iload_1
14: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
17: return

通过Jvm指令解析后,可知程序经过的步骤是这样的:

  1. 把50推入栈顶,栈顶值是50
  2. num1的值是50
  3. num1执行自增->num1=51
  4. 把2推入栈顶,栈顶值是2
  5. 执行50*2并保存到栈顶,栈顶值是100
  6. 把栈顶值赋给num1->num1=100

同理,++i也好理解了,把上边程序的num1++改为++num1

结果102,再分析下执行步骤

 public static void main(java.lang.String[]);
Code:
0: bipush 50 //把50推入栈顶top
2: istore_1 //将50保存到第二个局部变量中->num1=50
3: iinc 1, 1 //将50执行加1->50+1 局部变量num1值是51
6: iload_1 //把局部变量num1的值推入栈顶,此时栈顶值top是51
7: iconst_2 //把2推入栈顶
8: imul //把51和2相乘,并把结果102推入栈顶,此时栈顶值top是102
9: istore_1 //把102保存到第二个局部变量中->num1=102
10: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
13: iload_1
14: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
17: return

通过Jvm指令解析后,可知程序经过的步骤是这样的:

  1. 把50推入栈顶,栈顶值是50
  2. num1的值是50
  3. num1执行自增->num1=51
  4. 把num1的值推入栈顶,栈顶的值是51
  5. 把2推入栈顶,栈顶值是2
  6. 执行51*2并保存到栈顶,栈顶值是102
  7. 把栈顶值赋给num1->num1=102

结束

ok,分析结束,又温习了一遍指令,记录一下

最新文章

  1. Centreon插件nagvis
  2. This is usually caused by using Struts tags without the associated filter. Struts tags are only usable when the request has p
  3. gcc/交叉编译
  4. c++11:function的用法
  5. 【UVA1371】Period (二分+DP)
  6. apache 创建虚拟目录
  7. 走FILTER效率高的2种情况
  8. 判断iframe页面是否加载完成
  9. win10 uwp 进度条 Marquez
  10. linux 管理权限
  11. 剑指Offer——简述堆和栈的区别
  12. tp5的include 标签 不能用了么
  13. win10安装windows live writer 错误:OnCatalogResult:0x80190194
  14. 消费Restful的web服务(三)
  15. 你不知道的JavasScript上篇&#183;第三章&#183;对象
  16. Xilinx FPGA 的PCIE 设计
  17. [Linux]如何查看系统的Time Slice
  18. PyQt4信号与槽
  19. inotify+rsync安装配置
  20. ubuntu遇到的问题

热门文章

  1. 洛谷P1091合唱队形(DP)
  2. 【PAT甲级】1013 Battle Over Cities (25 分)(并查集,简单联通图)
  3. Day1-C-CF-1144A
  4. rhel7 系统服务——unit(单元)
  5. Navicat相关注册码
  6. swift正点
  7. 【转载】Git设置单个文件上传大小
  8. ADV-298 和谐宿舍2 动态规划
  9. java并发AtomicReference
  10. PaperWeek1