JVM学习–(三)类文件结构
本节会主要通过《深入理解JAVA虚拟机》上的一个实例,通过自己重新编译分析,来呈现class文件的结构。
一.源码文件
package org.fenixsoft.clazz;
public class TestClass {
private int m;
public int inc(){
return m+1;
}
}
二.经过javac编译后的class文件
CAFEBABE0000003400130A0004000F09000300100700110700120100016D010001490100063C696E69743E010003282956010004436F646501000F4C696E654E756D6265725461626C65010003696E6301000328294901000A536F7572636546696C6501000E54657374436C6173732E6A6176610C000700080C0005000601001D6F72672F66656E6978736F66742F636C617A7A2F54657374436C6173730100106A6176612F6C616E672F4F626A6563740021000300040000000100020005000600000002000100070008000100090000001D00010001000000052AB70001B100000001000A000000060001000000020001000B000C000100090000001F00020001000000072AB400020460AC00000001000A000000060001000000050001000D00000002000E
三.经过javap反编译后
public class org.fenixsoft.clazz.TestClass
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #4.#15 // java/lang/Object."<init>":()V
#2 = Fieldref #3.#16 // org/fenixsoft/clazz/TestClass.m:I
#3 = Class #17 // org/fenixsoft/clazz/TestClass
#4 = Class #18 // java/lang/Object
#5 = Utf8 m
#6 = Utf8 I
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 inc
#12 = Utf8 ()I
#13 = Utf8 SourceFile
#14 = Utf8 TestClass.java
#15 = NameAndType #7:#8 // "<init>":()V
#16 = NameAndType #5:#6 // m:I
#17 = Utf8 org/fenixsoft/clazz/TestClass
#18 = Utf8 java/lang/Object
{
public org.fenixsoft.clazz.TestClass();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 2: 0
public int inc();
descriptor: ()I
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: getfield #2 // Field m:I
4: iconst_1
5: iadd
6: ireturn
LineNumberTable:
line 5: 0
}
SourceFile: "TestClass.java"
四.Class文件的具体分析(可以与反编译码一起看)
CAFEBABEJAVA魔数
0000次版本号
0034主版本号
0013常量池容量(有18个常量,因为第0个特殊考虑为空)
常量池部分:
#1
0A类中方法符号引用
0004引用4号常量
000F引用15号常量
#2
09字段的符号引用
0003引用3号常量
0010引用10号常量
#3
07类或接口的符号引用
0011引用11号常量
#4
07类或接口的符号引用
0012引用12号常量
#5
01字符串引用
0001长度为1个字节
6D查询为m
#6
01字符串引用
0001长度为1个字节
49查询为I
#7
01字符串引用
0006长度为6个字节
3C696E69743E查询为
#8
01字符串引用
0003长度为3个字节
282956查询为()V
#9
01字符串引用
0004长度为4个字节
436F6465查询为Code
#10
01字符串引用
000F长度为15个字节
4C696E654E756D6265725461626C65查询为LineNumberTable
#11
01字符串引用
0003长度为3个字节
696E63查询为inc
#12
01字符串引用
0003长度为3个字节
282949查询为()I
#13
01字符串引用
000A长度为10个字节
536F7572636546696C65查询为SourceFile
#14
01字符串引用
000E长度为14个字节
54657374436C6173732E6A617661查询为TestClass.java
#15
0C字段或方法的部分符号引用
0007引用7号常量
0008引用8号常量
#16
0C字段或方法的部分符号引用
0005引用5号常量
0006引用6号常量
#17
01字符串引用
001D长度为29个字节
6F72672F66656E6978736F66742F636C617A7A2F54657374436C617373查询为org/fenixsoft/clazz/TestClass
#18
01字符串引用
0010长度为16个字节
6A6176612F6C616E672F4F626A656374查询为java/lang/Object
类信息:
0021访问标志:super+public
0003类索引:常量池中3号常量
0004父类索引:常量池4号常量
0000接口索引:接口索引集合大小为0,即没有
字段表集合(用来描述接口或类中声明的对象):
0001 容量计数器,里面只有1个字段
0002 访问标志:private
0005 字段的名字:第5号常量
0006标识字符:常量池第6号常量,I代表int
0000属性表:没有属性
方法信息:
0002方法的个数:2个
第一个方法:
0001方法的访问权限:public
0007方法的名字:第7号常量–初始方法
0008描述符:第8号常量
0001方法里有一项属性
0009属性对应的是9号常量,此属性是字节码描述的,Code
0000001D属性长度为:29(只包含自定义的属性长度,为整个属性表长度减去6)
0001操作栈深度为1
0001局部变量表储存空间为1
00000005字节码区域长度
字节码区域:
2A aload_0
B7 invokespecial
0001 1号常量
B1 return
0000 异常表长度为0,意思是没有异常表
0001字节码区域有一项属性
000A 常量池中的第10号:LineNumberTable
00000006 长度为6
0001行号表长度为1
00000002字节码第0行对应了源码的第2行
第二个方法:
0001访问标志:public
000B 方法名字:第11号常量 inc
000C 描述信息:返回值int
0001 属性表数量1个
0009说明这是个code
0000001F自定义长度为31
0002操作栈深度
0001局部变量表深度
00000007字节码区域长度:7
字节码区域:
2A:aload_0
B4:get field
0002:2号常量
04:iconst_1
60:iadd
AC:ireturn
0000没有异常表
0001属性表有1个
000A常量池10号:LineNumberTable
00000006长度为6
0001行号表长度为1
00000005第0行对应源码第5行
额外信息:
0001附加属性还有1个
SourceFile:
000D常量池第13号常量,说明是个SourceFile
00000002长度为2
000E对应为14号常量:源码文件位置。