文章目录
一、自增自减运算符
面试题:
public class Test01 {
public static void main(String[] args) {
int i = 1;
i = i++;
int j = i++;
int k = i + ++i * i++;
System.out.println(i);// 4
System.out.println(j);// 1
System.out.println(k);// 11
}
}
1.1 基础自增举例
//再看一个基础得例子
int i = 1;
i = i++;
//这里变量i还是等于1的
int j = i++;
System.out.println(i);// 2
System.out.println(j);// 1
参考博文 https://blog.csdn.net/qq_37937537/article/details/79931157
涉及到操作数栈与局部变量值的区别
粗略理解:
首先看 i= i++; 的操作
要清楚这个语句的步骤,第一步是先算右边的 i++ ,第二步将右边的结果赋值给变量 i
那么 i ++ 的结果大家都知道,还是 1 。
那么这个结果赋值给变量 i ,i 仍然 等于 1 .
原理详解:
明确一个知识点:自增运算是在局部变量表中进行,赋值语句是将操作数栈的结果取出。
为什么 i++ 叫做“先赋值后运算”?
(1)i ++ 时,先将 i 的值压入操作数栈。
(2)随后 i 进行自增操作,局部变量表中值自增为 2
(3)最后执行赋值操作,将操作数栈 中的结果,赋值给变量 i,仍然是 1
字节码逐条分析:
0 iconst_1 //常量值1
1 istore_1 //将常量值1存储到局部变量表--变量1
2 iload_1 //取变量1到操作数栈
3 iinc 1 by 1 //自增,在局部变量表
6 istore_1 //操作完毕,将操作数栈的栈顶值取出,赋给局部变量表对应变量。也就是将值1又赋给变量1
7 iload_1 //加载变量1到操作数栈
8 iinc 1 by 1 //局部变量自增 i变2
11 istore_2 //操作完毕,操作数栈顶值1赋给变量j(变量2),所以变量j值为1
12 getstatic #2 <java/lang/System.out>
15 iload_1
16 invokevirtual #3 <java/io/PrintStream.println>
19 getstatic #2 <java/lang/System.out>
22 iload_2
23 invokevirtual #3 <java/io/PrintStream.println>
26 return
1.2 面试题举例
对于K的求值,这里说一下我的粗暴理解
i ++ 是先将操作数压入操作数栈当中,然后局部变量表自增,最后从操作数栈取出赋值给变量 i。
++ i 是先在局部变量表 i 自增,再将 i 的值压入操作数栈,最后执行赋值操作取操作数栈的值赋值给变量 i。
所以对比发现这个区别就是 将 i 的值压入操作数栈 和 局部变量中自增 的顺序,决定了这两个东西最后结果的差异。你明白他俩到底哪里不一样才会出现不同结果了吗?
下面看一个我瞎画得图解:
柴林燕老师得PPT讲解:
字节码分析
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
24 getstatic #2 <java/lang/System.out>
27 iload_1
28 invokevirtual #3 <java/io/PrintStream.println>
31 getstatic #2 <java/lang/System.out>
34 iload_2
35 invokevirtual #3 <java/io/PrintStream.println>
38 getstatic #2 <java/lang/System.out>
41 iload_3
42 invokevirtual #3 <java/io/PrintStream.println>
45 return