一 代码
public class MethodAreaDemo {
public static void main(String args[]) {
int x = 500;
int y = 100;
int a = x / y;
int b = 50;
System.out.println(a+b);
}
}
二 对应常量池
#1 = Methodref #5.#24 // java/lang/Object."<init>":()V
#2 = Fieldref #25.#26 // java/lang/System.out:Ljava/io/PrintStream;
#3 = Methodref #27.#28 // java/io/PrintStream.println:(I)V
#4 = Class #29 // com/atguigu/java1/MethodAreaDemo
#5 = Class #30 // java/lang/Object
#6 = Utf8 <init>
#7 = Utf8 ()V
#8 = Utf8 Code
#9 = Utf8 LineNumberTable
#10 = Utf8 LocalVariableTable
#11 = Utf8 this
#12 = Utf8 Lcom/atguigu/java1/MethodAreaDemo;
#13 = Utf8 main
#14 = Utf8 ([Ljava/lang/String;)V
#15 = Utf8 args
#16 = Utf8 [Ljava/lang/String;
#17 = Utf8 x
#18 = Utf8 I
#19 = Utf8 y
#20 = Utf8 a
#21 = Utf8 b
#22 = Utf8 SourceFile
#23 = Utf8 MethodAreaDemo.java
#24 = NameAndType #6:#7 // "<init>":()V
#25 = Class #31 // java/lang/System
#26 = NameAndType #32:#33 // out:Ljava/io/PrintStream;
#27 = Class #34 // java/io/PrintStream
#28 = NameAndType #35:#36 // println:(I)V
#29 = Utf8 com/atguigu/java1/MethodAreaDemo
#30 = Utf8 java/lang/Object
#31 = Utf8 java/lang/System
#32 = Utf8 out
#33 = Utf8 Ljava/io/PrintStream;
#34 = Utf8 java/io/PrintStream
#35 = Utf8 println
#36 = Utf8 (I)V
三 字节码执行过程展示
1 执行前,方法区、虚拟机栈以及程序计数器的样子 2 将操作数 500 放入到操作数栈中。3 弹出操作数栈栈顶 500,保存到本地变量表1。
4 把 100 这个数值压入操作数栈 5 弹出操作数栈栈顶 100,保存到本地变量表2。 6 读取本地变量1压入操作数栈7 读取本地变量2压入操作数栈
8 将栈顶两个 int 类型取出并相除,结果5入栈。
9 将5保存到本地变量3,然后将50压入操作数栈
10 将栈顶 int 类型值保存到局部变量表4中。11 获取类或接口字段的值并将其压入操作数栈
#2 在常量池经过一番拼接,最终拼接成: java/lang/System.out:Ljava/io/PrintStream,它是Fieldref 类型。12 将本地变量3取出,压入操作数栈。
13 将本地变量4取出,压入操作数栈。 14 将栈顶两个 int 类型取出并相加,结果55入栈。 15 调用 invokevirtual #3 #3 = Methodref #27.#28 // java/io/PrintStream.println:(I)V16 main方法执行结束,进行 return
整个过程中,程序计数器始终计算的都是当前代码运行的位置,目的是为了方便记录方法调用后能够正常返回,或者是进行了 CPU 切换后,也能回来到原来的代码进行 执行。