JVM之Class文件分析详解
逐个字节分析Class文件。了解Class文件内部结构。
原始类文件:
这个类直接拿了知乎的一个类,分析是很简单,只是因为重新画图比较麻烦,不想再做重复的苦力工作(地址(https://zhuanlan.zhihu.com/p/23068093)ps:作者仅仅提供了类和图,并无解析。)
1 | package com.vonzhou.learn.jvm.klass; |
Class结构体
一个Class文件可以用如下的结构体抽象:
Step by Step
接下来就是对照着字节码和JVM规范阅读的过程,对自己多点耐心。
Class魔数和版本
常量池计数器和常量池
注意:常量池内常量的真实数量是 常量池计数器-1
那么接下来就是这三个了:
访问标志
这里
为什么是0021呢?因为 0X0001|0X0020 = 0X0021。
类索引,父类索引
接下来的2B是this_class指向我们的类名, super_class指示父类。
这里没有实现接口:
字段计数器和字段表集合
fields_count以后进入字段表集合
方法计数器和方发表集合
首先进入方法计数器。
从上可以看出,关键的不同点在于attribute_info字段。这是属性表集合,下面附上属性表集合的一般结构。
从上面两个图可以看出属性表前两个字段时固定的,关键在于第三个字段各有不同,比如方法表的属性表Code的完整格式为下图
接下来就对Code属性表进行梳理:
属性计数器和属性表集合
属性表集合中的SourceFile:
由属性计数器后的0010计算十进制数为
下面的DEC为16,所以找到第16个常量为
没错了,是SourceFile
附上javap -version 验证解析结果
使用javap解析出来的结果中没有包含LocalVariableTable字段,需要在使用javac编译java中时,加上-g的参数,生成的class文件中才带有LocalVariableTable的信息。LocalVariableTable属性:用于描述栈帧中局部变量表中的变量与Java源码中定义的变量之间的关系,非运行时必需属性,默认不会生成至Class文件中,可以使用Javac的-g:none或-g:vars关闭或要求生成该项属性信息。
另外:LineNumberTale属性:用于描述Java源码的行号与字节码行号之间的对应关系,非运行时必需属性,会默认生成至Class文件中,可以使用Javac的-g:none或-g:lines关闭或要求生成该项属性信息。
具体编译过程:
1 | javac -g -d . Foo.java |
1 | javap -v com.vonzhou.learn.jvm.klass.Foo |
1 | ca fe ba be 20 20 20 34 20 16 0a 20 04 20 12 09 20 03 20 13 07 20 14 07 20 15 01 20 01 6d 01 20 01 49 01 20 06 3c 69 6e 69 74 3e 01 20 03 28 29 56 01 20 04 43 6f 64 65 01 20 0f 4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65 01 20 12 4c 6f 63 61 6c 56 61 72 69 61 62 6c 65 54 61 62 6c 65 01 20 04 74 68 69 73 01 20 21 4c 63 6f 6d 2f 76 6f 6e 7a 68 6f 75 2f 6c 65 61 72 6e 2f 6a 76 6d 2f 6b 6c 61 73 73 2f 46 6f 6f 3b 01 20 03 69 6e 63 01 20 03 28 29 49 01 20 0a 53 6f 75 72 63 65 46 69 6c 65 01 20 08 46 6f 6f 2e 6a 61 76 61 0c 20 07 20 08 0c 20 05 20 06 01 20 1f 63 6f 6d 2f 76 6f 6e 7a 68 6f 75 2f 6c 65 61 72 6e 2f 6a 76 6d 2f 6b 6c 61 73 73 2f 46 6f 6f 01 20 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 20 21 20 03 20 04 20 20 20 01 20 02 20 05 20 06 20 20 20 02 20 01 20 07 20 08 20 01 20 09 20 20 20 2f 20 01 20 01 20 20 20 05 2a b7 20 01 b1 20 20 20 02 20 0a 20 20 20 06 20 01 20 20 20 03 20 0b 20 20 20 0c 20 01 20 20 20 05 20 0c 20 0d 20 20 20 01 20 0e 20 0f 20 01 20 09 20 20 20 31 20 02 20 01 20 20 20 07 2a b4 20 02 04 60 ac 20 20 20 02 20 0a 20 20 20 06 20 01 20 20 20 07 20 0b 20 20 20 0c 20 01 20 20 20 07 20 0c 20 0d 20 20 20 01 20 10 20 20 20 02 20 11 |
1 | E:\JVM>javap -v com.vonzhou.learn.jvm.klass.Foo |
再次附上没有 -g 的结果:
1 | ca fe ba be 20 20 20 34 20 13 0a 20 04 20 0f 09 20 03 20 10 07 20 11 07 20 12 01 20 01 6d 01 20 01 49 01 20 06 3c 69 6e 69 74 3e 01 20 03 28 29 56 01 20 04 43 6f 64 65 01 20 0f 4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65 01 20 03 69 6e 63 01 20 03 28 29 49 01 20 0a 53 6f 75 72 63 65 46 69 6c 65 01 20 08 46 6f 6f 2e 6a 61 76 61 0c 20 07 20 08 0c 20 05 20 06 01 20 1f 63 6f 6d 2f 76 6f 6e 7a 68 6f 75 2f 6c 65 61 72 6e 2f 6a 76 6d 2f 6b 6c 61 73 73 2f 46 6f 6f 01 20 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 20 21 20 03 20 04 20 20 20 01 20 02 20 05 20 06 20 20 20 02 20 01 20 07 20 08 20 01 20 09 20 20 20 1d 20 01 20 01 20 20 20 05 2a b7 20 01 b1 20 20 20 01 20 0a 20 20 20 06 20 01 20 20 20 03 20 01 20 0b 20 0c 20 01 20 09 20 20 20 1f 20 02 20 01 20 20 20 07 2a b4 20 02 04 60 ac 20 20 20 01 20 0a 20 20 20 06 20 01 20 20 20 07 20 01 20 0d 20 20 20 02 20 0e |
1 | E:\JVM>javac -d . Foo.java |
参考
《深入理解Java虚拟机》周志明,
另外找到的其他关于Class文件解析的文章有:
https://www.cnblogs.com/timlong/p/8143839.html
https://www.cnblogs.com/noteless/p/9540876.html#0
https://www.jianshu.com/p/d0f3e361f92e
https://www.jb51.net/article/116203.htm(这个有对文中没有详细解释的method方法的属性的解释)