学习记录310@int i = 0; i = i++;System.out.println(“i的值为:“+i);

以下代码,这是Java关于自增自减的经典案例,单单靠先赋值后自增,或者先自增后赋值的方式是无法正确解题的,需要JVM的底层知识。

public class Test{
    
    
	
	public static void main(String[] args){
    
    
		int i = 0;   
		i = i++;
		System.out.println(i);
		
		int j = 0;   
		j = ++j;
		System.out.println(j);
	}
}

答案是
在这里插入图片描述
对于以上答案,j的值几乎没什么可争论的,但是i的值可能存在较大的争议,大部分人可能认为是也是1,后面再解释。

清空思路

在解析之前,先清空思维,就算是“先赋值后自增,或者先自增后赋值”这句话也是需要清空的。
这句话的更好理解的改进是:

i++:先使用后自增,++i:先自增后使用
那么,使用什么呢?使用i++,或者++i ?其实就是使用i,无论i++,还是++i,真正要使用的其实是i本身,但是这个i本身的值代表了i++,或者++i,仅此而已
比如对于以上j的代码,++j表明,先自增后使用,也就是j先变为1,然后j = ++j这句代码再使用,使用什么呢,表面上是++j,但实际上是j本身,这个时候就是j=1(先自增了,再使用自增后的j)
个人认为比将赋值替换为使用更加具有扩展性,因为有些时候并不是赋值,而是参与其他运算,比如k=++i + 100/2

结果偏差

对于j的值,按照以上的分析,可知答案是1;
对于i的值,按照”i++:先使用后自增,++i:先自增后使用“的思路,i = i++;的代码中,i++,先使用,也就是i=0,然后i自增,变为了1,最后再打印i,就应该是1才对,但是很遗憾,并不是如此,这部分需要用jvm的底层去分析。

jvm基础

很难用少量篇幅将 jvm基础介绍完全,特别是内存结构,特别是栈帧,特别是,操作数栈和局部变量表,这里仅仅简单的描述,后面能用即可。
java代码经过编译,变为.class文件,然后经过虚拟机变为机器码,再输入内存进行运行,因此,要了解真正的运行情况,可以去查看.class文件,相当于对我们写的代码进行了翻译,代表着代码运行的底层逻辑。
运行底层结构,如下图(只是一个例子,不是本题的图):
在这里插入图片描述

  • 方法区就是我们.class文件反编译后的比较容易理解内容,也就是代码运行底层逻辑;
  • 执行引擎就是当前执行哪一句代码;
  • 栈帧中时真正运行时的行为,其中,左边是局部变量表,代表着有哪些局部变量,每个变量都对应一个槽位slot,比如变量b对应的是2号槽位,用于放变量的值,右边是操作数栈(注意先进后出数据结构),对于变量的值的操作,都会在操作数栈中进行,比如b=10这句代码,系统会先将10放入操作数栈的栈顶(底层是bipush 10语句),然后将10弹出,或者复制出来,赋值给b,也就是将10放到b对应的槽内(底层是istore_2)
  • 注意方法区内的单词就是一些命令,比如bipush 10(把10压入栈),istore_1(将栈顶的元素存储到槽1对应变量处),iinc 1 1(槽1处的变量自增1),iload_1(槽1处的变量的值压入操作数栈),iadd(加法运算),关于这些单词,可见JVM 之 (11)字节码指令

关于案例的底层解析

首先使用javap对.class文件反编译:javap -v Test
在这里插入图片描述

得到结果(重要部分):
在这里插入图片描述
解释如下表:
注意i的槽位为1,j的槽位为2
在这里插入图片描述
推荐视频jvm底层解析a++原理

猜你喜欢

转载自blog.csdn.net/weixin_44663675/article/details/108628541
I
今日推荐