博文前言:
前几天在一个帖子中看到有这么几行代码,觉得有点儿意思,结果差点儿想少了!
public class JvmTest{
public static void main(String [] args){
int j = 0;
for(int i = 0;i<10;i++){
j = (j++);
}
System.out.println(j);//0
}
}
这几行代码主要考察的是++i和i++的区别!主要用到的就是java虚拟机栈!
1.1 java虚拟机栈:
java虚拟机栈是线程私有的,他与线程的声明周期同步。虚拟机栈描述的是java方法执行的内存模型,每个方法执行都会创建一个栈帧,栈帧主要包含局部变量表、操作数栈、动态连接、方法出口。
1.1.1 我们可以把上述代码简化然后使用javap命令进行反汇编
1)简化后的代码
public class JvmTest {
public static void main(String[] args) {
int i = 0;
int j = 0;
j = i++;
System.out.println(j);//0
}
}
2) 使用 javap -c JvmTest >> JvmTxt.txt
对JvmTest.class 进行反汇编,并生成到JvmTxt.txt文件
Compiled from "JvmTest.java"
public class JvmTest {
public JvmTest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_0 // iconst_0:将0压栈
1: istore_1 // istore_1: 将0存入局部变量1,此时局部变量表中局部变量1为i:操作数栈中的0出栈并赋值给i ,现在局部变量表中i =0
2: iconst_0 // iconst_0:将0压栈
3: istore_2 // istore_2:将0存入局部变量2,此时局部变量表中局部变量1为j:操作数栈中的0出栈并赋值给j,现在局部变量表中j =0
4: iload_1 // iload_1:从局部变量1中装载0 ,将i的值压栈到操作数栈
5: iinc 1, 1 // iinc 1, 1 :把常量1加到局部变量1(i)此时 i = 1
8: istore_2 // istore_2 将int类型值存入局部变量2:将0出栈,将并 0赋值给j,此时j = 0
9: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
12: iload_2 // iload_2 从局部变量2中装载int类型值: 将局部变量表中j 的值0 压栈,此时栈顶元素为0
13: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
16: return
}
3)这里面出现的几个指令集的含义,其他指令集含义请自行百度
iconst_0 将int类型常量0压入栈
istore_1 将int类型值存入局部变量1
iconst_0 将int类型常量0压入栈
istore_2 将int类型值存入局部变量2
iload_1 从局部变量1中装载int类型
iinc 把一个常量值加到一个int类型的局部变量上
getstatic 从类中获取静态字段
iload_2 从局部变量2中装载int类型值
调度对象的实便方法:invokevirtual
经过如上分析我们可以明确得出程式最后输出的值是0。
1.1.2 类比第一个案例
同样的道理,第一个案例中尽管循环多次,但最后会重新将局部变量表中的j =0的值入栈,所以最后的输出结果依旧是0 ,这个过程都是在java栈中的操作数栈中完成的
如下是jvm的内存结构