zoukankan      html  css  js  c++  java
  • 神奇的i++

    神奇的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:
    otepadd++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,分析结束,又温习了一遍指令,记录一下

    作者:往霄龙
    求其上者得其中,求其中者得其下
  • 相关阅读:
    【并发编程】多线程并发最佳实践
    【并发编程】死锁
    【并发编程】【JDK源码】J.U.C--线程池
    【并发编程】【JDK源码】J.U.C--组件FutureTask、ForkJoin、BlockingQueue
    【JVM】关于类加载器准备阶段的一道面试题目
    【并发编程】【JDK源码】J.U.C--AQS 及其同步组件(2/2)
    【并发编程】线程安全策略
    JSP 9大内置对象详解
    Jquery中的bind(),live(),delegate(),on()绑定事件方式
    阻止事件冒泡
  • 原文地址:https://www.cnblogs.com/JQKA/p/12100888.html
Copyright © 2011-2022 走看看