一.class文件
根据JVM规范
注:
un : n个字节
info :表
1、魔数
0~3个字节,表示它是否是【class】类型的文件
ca fe ba be
2、版本
4~7字节,表示类的版本 00 34(52)表示的是java 8
00 00:小版本号
00 34:主版本号
3、常量池
8~9字节,表示常量池长度,00 23(35)表示常量池有#1~#34,注意#0项不计入,也没有值
简要分析:
第#1项 0a表示一个Method(方法)信息, 接下来的4个字节代表方法信息 00 06和 00 15(21)表示它引用了常量池中#6和#23项来获得这个成员变量的【所属类名】和【成员变量名】
第#2项 09 表示这是一个Field信息,00 16(22)和 00 17(23)表示它引用了常量池中#22 和 #23项来获得这个成员变量的【所属类】和【成员变量名】
第#3项 08 表示一个字符串常量名称,00 18 (24)表示它引用了常量池中#24项
4 访问标识与继承信息
5 Field信息 fields_count
6 Method(方法信息) 信息
7附加属性
二.字节码指令
自己分析类文件结构太麻烦了,Oracle提供了javap工具来反编译class文件
javap -v HelloWorld.class
先是一些类信息
名字,最后修改时间,大小,源文件是谁,版本号等
常量池:
简要分析内容
#1:方法引用: 引用了第6项和21项, Object类 init方法
#2: 成员变量引用:引用了22 和 23 项 out变量+Pri–类型
#3 : 字符串 : 对应Hello world
#4 :方法引用:
方法信息
构造方法分析:
参数类型,访问修饰符 ,代码信息Code
stack:最大操作数栈的深度
locals:局部变量表的长度
args_ize:参数长度
aload_0:把局部变量的第0项加载到操作数栈
0 1 4代表的是字节码的代码行号
line 4 : 0 4:源文件中的行号 对应 0:字节码中的行号
LocalVariableTable:本地变量表
变量的作用范围5行 0-4
main方法的分析
参数类型是字符串数组
访问修饰符号:public static
code:方法属性
2.2图解方法执行流程
2.2.1原始java代码
2.2.2 类加载的时候,常量池中的数据放到运行时常量池
2.2.3方法字节码载入方法区
2.2.4 main线程开始运行,分配栈帧内存
栈帧中分配局部变量表和操作数栈
操作数栈4个字节
2.2.5
bipush
小的数字是和字节码指令存在一起的,在方法区中,超过short范围的数字存入了常量池
istore_1
将操作数栈顶数据弹出,存入局部变量表的slot 1
(a=10)
ldc #3
从常量池加载#3数据到操作数栈
ldc:从常量池取并压栈,所以这个范围的int是存在常量池
注意:short.max_value是32767 所以 32768=short.max_value+1
getstatic #4
从常量池中找到了一个成员变量的引用
是System.out这个成员变量
System.out对象存在于堆里面,所以就到堆里面找到这个对象
然后获得这个对象的引用,放到操作数栈
iload_3
invokvirtual #5
找到常量池中的#5项
定位到方法区 java/io/PrintStream.println:(I)V方法
生成新的栈帧(分配locals、stack等)
传递参数,执行新的栈帧中的字节码
执行完毕,弹出栈帧
清除main操作数栈内容
return
完成main方法的调用,弹出main栈帧
程序结束