自增变量(从 i++ 和 ++i 说起局部变量表和操作数栈)

 

 

import static java.lang.System.*;

public class Test01 {

   public static void main(String[] args){
       int i=1;
       i=i++;
       int j=i++;
       int k=i+ ++i * i++;
       out.println("i="+i);
       out.println("j="+j);
       out.println("k="+k);
   }

 为什么是这个结果呢?我们先来看看 Java 虚拟机栈的知识点。

Java 内存可以粗糙的区分为堆内存(Heap)和栈而不是队列呢?很容易理解,因为方法内存(Stack),其中栈就是现在说的虚拟机栈,或者说是虚拟机栈中局部变量表部分。

至于为什么是栈而不是队列呢?很容易理解,因为方法调用链是最后一个调用先返回的。用队列显然不合适。

Java 虚拟机栈也是线程私有的,生命周期与线程相同。任何一个方法的执行也都是一个线程来调用的,所以前面这句话就很好理解了。

每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用、动态链接、程序出口等信息。每一个方法从调用到执行完成的过程,对应一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。

 

 ä» i++ å ++i 说起å±é¨åé表åæä½æ°æ ä» i++ å ++i 说起å±é¨åé表åæä½æ°æ 

局部变量表存放了编译器可知的各种基本数据类型(boolean,byte,char,short,int,float,long,double)、对象引用(reference类型,不同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)和returnAddressleixing (字节码指令地址)。局部变量表所需内存在编译期间完成分配,运行期间不会改变。

和局部变量区一样,操作数栈也是被组织成一个以字长为单位的数组。但是和前者不同的是,它不是通过索引来访问,而是通过标准的栈操作—压栈和出栈—来访问的。比如,如果某个指令把一个值压入到操作数栈中,稍后另一个指令就可以弹出这个值来使用。

虚拟机在操作数栈中存储数据的方式和在局部变量区中是一样的:如int、long、float、double、reference和returnType的存储。对于byte、short以及char类型的值在压入到操作数栈之前,也会被转换为int。

0 iconst_1
 1 istore_1
 2 iload_1
 3 iinc 1 by 1
 6 istore_1
 7 iload_1
 8 iinc 1 by 1
11 istore_2
12 iload_1
13 iinc 1 by 1
16 iload_1
17 iload_1
18 iinc 1 by 1
21 imul
22 iadd
23 istore_3

所以,我们现在解释一下上面的代码。int i = 1;发生了两个过程,iconst_1 是将 int 型的 1 推送至栈顶。istore_1 把栈顶的元素弹出,并赋值给局部变量表中位置为“1”的变量,此时指变量i。这两句就相当于 int i = 1;  i = i++; 代码解释:iload_1 把局部变量表中位置为“1”的变量加载到栈顶,即把 i 的值加载到栈顶。iinc 1 by 1,将局部变量表中位置为“1”的 i 加 1(i++是直接在局部变量表加的,没有在栈里运算),此时局部变量表中 i 的结果为 2。然后 istore_1 把栈顶的元素弹出,并赋值给局部变量表中位置为“1”的变量。所以 i 的值又被改为了 1。  int j = i++; 代码解释:iload_1 把局部变量表中位置为“1”的变量加载到栈顶,即把 i 的值加载到栈顶。iinc 1 by 1 将局部变量表中位置为“1”的 i 加 1,此时结果为 2,也就是局部变量表中 i 的结果为 2。istore_2 把栈顶的元素弹出并赋值给局部变量表中位置为“2”的 j。所以 j 是 1,但是 i 的值已经为 2。  int k = i + ++i * i++; 这个是最复杂的,我们直接看 JVM 指令即可。iload_1 把局部变量表中位置为“1”的变量加载到栈顶,即把 i 的值加载到栈顶,注意 i 的值此时是 2。iinc 1 by 1,i 自增,然后 i 就变成 3 了。接着两个 iload_1、iload_1分别把局部变量 i 压到栈了。所以栈中现在是 3、3、2。然后执行 iinc 1 by 1,i 又自增了,这时把局部变量表中的 i 就变成 4 了,注意这个 4 并未压入栈。之后 imul 进行乘法计算,栈中的前两个元素计算后是 9,之后执行 iadd 指令,也就是 9 + 2,结果为 11。最后 istore_3 把 11 从栈顶弹出,并赋值给 k,也就是局部变量表中位置为“3”的 k 的值是 11。

 

参考博客:从 i++ 和 ++i 说起局部变量表和操作数栈

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值