也许我这是在较真, 但是我们确实有时候就不小心就错写为这种情况了。

看如下代码:

public class Test{

        public static void main(String[] args){
                int a = 3;
                int b = 5;
                a = a++;
                b = ++b;
        }

}

  这时候, 如果输出 a 和 b ,那么 他们的值是什么? 答案是 a = 3; b = 6;

  如果你感到迷惑, 那么继续往下看, 如果你知道其中的原理,那么就不用看了。

我们利用 jdk 自带的两个命令(javac,javap)来看看 JVM 虚拟机到底在底层做了些什么。

建立一个文件 Test.java 并把上面的代码写入其中, 然后里用 javac 命令编译

wuqinglong@debian:~$ javac -g:vars Test.java

  然后利用 javap 命令查看 JVM 编译之后的虚拟机指令。

wuqinglong@debian:~$ javap -verbose Test

  输出如下内容

Classfile /home/wuqinglong/Test.class
  Last modified 2016-3-16; size 326 bytes
  MD5 checksum 2e2f3ec62c26d0e1e53bb121e83b9032
public class Test
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #3.#17         // java/lang/Object."<init>":()V
   #2 = Class              #18            // Test
   #3 = Class              #19            // java/lang/Object
   #4 = Utf8               <init>
   #5 = Utf8               ()V
   #6 = Utf8               Code
   #7 = Utf8               LocalVariableTable
   #8 = Utf8               this
   #9 = Utf8               LTest;
  #10 = Utf8               main
  #11 = Utf8               ([Ljava/lang/String;)V
  #12 = Utf8               args
  #13 = Utf8               [Ljava/lang/String;
  #14 = Utf8               a
  #15 = Utf8               I
  #16 = Utf8               b
  #17 = NameAndType        #4:#5          // "<init>":()V
  #18 = Utf8               Test
  #19 = Utf8               java/lang/Object
{
  public Test();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   LTest;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=3, args_size=1
         0: iconst_3    // 将int类型的3送到栈顶
         1: istore_1    // 将栈顶的int类型的值存储到slot为1的int类型的本地变量中,slot编号对应的变量名在后三行。
         2: iconst_5    // 将int类型的5送到栈顶
         3: istore_2    // 将栈顶的int类型的值存储到slot为2的int类型的本地变量中
         4: iload_1    // 将slot为1的int类型的本地变量加载到栈顶
         5: iinc          1, 1    // 将slot为1的本地int类型的变量的值加1
         8: istore_1    // 将栈顶的int类型的值存储到slot为1的本地变量中
         9: iinc          2, 1    // 将slot为2的本地intbeijing的变量的值加1
        12: iload_2    // 将slot为2的int类型的本地变量加载到栈顶
        13: istore_2    // 将栈顶的int类型的值存储到slot为2的int类型的本地变量中
        14: return    // 结束
      LocalVariableTable:    // 变量对应的slot编号如下
        Start  Length  Slot  Name   Signature
            0      15     0  args   [Ljava/lang/String;
            2      13     1     a   I
            4      11     2     b   I
}

  如果有点汇编知识的话,看上面的代码会比较好理解点, 如果没有学过汇编指令的话, 就看注释。

其中最主要的区别是:

  对于  a = a++;  JVM 进行的操作是:

    1. 将本地变量的值加载到栈顶  (注意: 这时候这个值是没有经过自增操作的)

    2. 对本地变量的值进行自增(对栈顶对象没有影响)

    3. 把栈顶变量的值存储到本地变量中(重新对本地变量赋值,栈顶变量的值并没有进行自增操作,自增操作是对本地变量进行操作的)

  对于  b = ++b;  JVM 进行的操作是:

    1. 将本地变量的值先自增

    2. 将自增完之后的本地变量的值加载到栈顶(注意:这时候这个值是经过了自增操作的)

    3. 将栈顶变量的值存储到本地变量中

Java中的自增问题(i=i++)的更多相关文章

  1. 【Java】【4】关于Java中的自增自减

    摘要:理解j = j++与j = ++j的区别:正确用法:直接用j++,不要用前两种 正文: import java.util.*; public class Test{ public static ...

  2. java中的自增问题

    运行下面这段代码,其结果是什么呢? package com.test; public class Inc { public static void main(String[] args) { Inc ...

  3. java中集合的增删改操作及遍历总结

      集合的增删改操作及遍历总结

  4. java中双向链表的增、删、查操作

    import java.util.NoSuchElementException; public class DoublyLinkedListImpl<E> { private Node h ...

  5. Java中的自增自减

    情况①: for (int i = 0; i < 100; i++) { j = 1 + j++; } System.out.println(j); 结果是 0 !! 这是由于在进行后自增/自减 ...

  6. Java中AtomicInteger的使用!!!

    今天在看Volley的源码的时候,看到里面使用了AtomicInteger这个类,曾经没用过,今天看了一下API学习了一下: 首先介绍一下这个类的用处,这个类主要是用来替换java中的自增和自减操作, ...

  7. Android(java)学习笔记186:对ListView等列表组件中数据进行增、删、改操作

    1.ListView介绍 解决大量的相似的数据显示问题 采用了MVC模式: M: model (数据模型) V:  view  (显示的视图) C: controller 控制器 入门案例: acit ...

  8. Android(java)学习笔记129:对ListView等列表组件中数据进行增、删、改操作

    1. ListView介绍 解决大量的相似的数据显示问题 采用了MVC模式: M: model (数据模型) V:  view  (显示的视图) C: controller 控制器 入门案例: aci ...

  9. java中如何理解:其他类型 + string 与 自增类型转换和赋值类型转换

    java中如何理解:其他类型 + string 与 自增类型转换和赋值类型转换 一.字符串与其他类型连接 public class DemoString{ public static void mai ...

随机推荐

  1. ALSA 学习小记

    对于playback snd_pcm_begin snd_pcm_commit, 貌似 commit给的frame才会使得alsa去把数据填充 转自 http://magodo.github.io/ ...

  2. CSS第二章

    1. 文本与字体属性: text-decoration:文本修饰线  none(去除修饰线).underline(下划线).overline(上划线).line-through(删除线) color: ...

  3. UILable

    //UILable的大小自适应实例 UILabel *myLable = [[UILabel alloc] initWithFrame:CGRectMake(, , , )];//设定位置与大小 [m ...

  4. 阿里云CentOS6上配置iptables

    参考:http://blog.abv.cn/?p=50 阿里云CentOS6默认没有启动iptables 1.检查iptables状态 [root@iZ94jj63a3sZ ~]# service i ...

  5. Druid 基础使用-操作篇(Pivot、plyql)

    一.Pivot  --9095 端口  二.基本sql 使用 .plysql--   http://plywood.imply.io/plyql  (下面的端口应该是8082,我这个地方做了端口转换) ...

  6. 解决VS2012上面EF字段说明备注没有的方法

    VS2012中的EF有一个BUG 如下: 明明在数据库上面是写有字段说明的到了EF上面就没有了很郁闷: 网络上面有一个解决方法如下: http://www.cnblogs.com/stone_w/ar ...

  7. Python用法摘要 BY 四喜三顺

    函数的定义:def function_name(parameters):    block    return expression 自带函数:abs(-9)    #取绝对值round(3.4)   ...

  8. ASP.NET程序中 抛出"Thread was being aborted. "异常(转)

    Thread was being aborted :中文意思 线程被终止 引用地址:http://support.microsoft.com/default.aspx/kb/312629/EN-US/ ...

  9. 十四、View Port 2.0

    1. 分为以下几类: (1) data classes: 用来访问scene中的geometry 和 shaders (2)scene override: 主要是用户自定义的drawing .shad ...

  10. 《Linux企业应用案例精解(第2版)》新书发售啦

    本书在出版当年就获得了不错的销量,同时被中国科学院国家科学图书馆.中国国家图书馆.首都图书馆.清华大学.北京大学等上百所国内综合性大学图书馆收录为馆藏图书,在IT业界赢得了良好的口碑.随后2012年年 ...