逐个字节分析Class文件。了解Class文件内部结构。
这个类直接拿了知乎的一个类,分析是很简单,只是因为重新画图比较麻烦,不想再做重复的苦力工作(地址(https://zhuanlan.zhihu.com/p/23068093)ps:作者仅仅提供了类和图,并无解析。)
package com.vonzhou.learn.jvm.klass;
public class Foo {
private int m;
public int inc() {
return m + 1;
}
}
一个Class文件可以用如下的结构体抽象:
接下来就是对照着字节码和JVM规范阅读的过程,对自己多点耐心。
注意:常量池内常量的真实数量是 常量池计数器-1
那么接下来就是这三个了:
这里
为什么是0021呢?因为 0X0001|0X0020 = 0X0021。
接下来的2B是this_class指向我们的类名, super_class指示父类。
这里没有实现接口:
fields_count以后进入字段表集合
首先进入方法计数器。
从上可以看出,关键的不同点在于attribute_info字段。这是属性表集合,下面附上属性表集合的一般结构。
从上面两个图可以看出属性表前两个字段时固定的,关键在于第三个字段各有不同,比如方法表的属性表Code的完整格式为下图
接下来就对Code属性表进行梳理:
属性表集合中的SourceFile:
由属性计数器后的0010计算十进制数为
没错了,是SourceFile
使用javap解析出来的结果中没有包含LocalVariableTable字段,需要在使用javac编译java中时,加上-g的参数,生成的class文件中才带有LocalVariableTable的信息。LocalVariableTable属性:用于描述栈帧中局部变量表中的变量与Java源码中定义的变量之间的关系,非运行时必需属性,默认不会生成至Class文件中,可以使用Javac的-g:none或-g:vars关闭或要求生成该项属性信息。
另外:LineNumberTale属性:用于描述Java源码的行号与字节码行号之间的对应关系,非运行时必需属性,会默认生成至Class文件中,可以使用Javac的-g:none或-g:lines关闭或要求生成该项属性信息。
具体编译过程:
javac -g -d . Foo.java
javap -v com.vonzhou.learn.jvm.klass.Foo
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
E:\JVM>javap -v com.vonzhou.learn.jvm.klass.Foo
Classfile /E:/JVM/com/vonzhou/learn/jvm/klass/Foo.class
Last modified 2019-5-3; size 391 bytes
MD5 checksum 4d9e593620f49a9114d834ec5d923986
Compiled from "Foo.java"
public class com.vonzhou.learn.jvm.klass.Foo
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #4.#18 // java/lang/Object."":()V
#2 = Fieldref #3.#19 // com/vonzhou/learn/jvm/klass/Foo.m:I
#3 = Class #20 // com/vonzhou/learn/jvm/klass/Foo
#4 = Class #21 // java/lang/Object
#5 = Utf8 m
#6 = Utf8 I
#7 = Utf8
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 Lcom/vonzhou/learn/jvm/klass/Foo;
#14 = Utf8 inc
#15 = Utf8 ()I
#16 = Utf8 SourceFile
#17 = Utf8 Foo.java
#18 = NameAndType #7:#8 // "":()V
#19 = NameAndType #5:#6 // m:I
#20 = Utf8 com/vonzhou/learn/jvm/klass/Foo
#21 = Utf8 java/lang/Object
{
public com.vonzhou.learn.jvm.klass.Foo();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/vonzhou/learn/jvm/klass/Foo;
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 7: 0
LocalVariableTable:
Start Length Slot Name Signature
0 7 0 this Lcom/vonzhou/learn/jvm/klass/Foo;
}
SourceFile: "Foo.java"
再次附上没有 -g 的结果:
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
E:\JVM>javac -d . Foo.java
E:\JVM>javap -v com.vonzhou.learn.jvm.klass.Foo
Classfile /E:/JVM/com/vonzhou/learn/jvm/klass/Foo.class
Last modified 2019-5-3; size 291 bytes
MD5 checksum 45262c23d72e75c78347d2f05b918bee
Compiled from "Foo.java"
public class com.vonzhou.learn.jvm.klass.Foo
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #4.#15 // java/lang/Object."":()V
#2 = Fieldref #3.#16 // com/vonzhou/learn/jvm/klass/Foo.m:I
#3 = Class #17 // com/vonzhou/learn/jvm/klass/Foo
#4 = Class #18 // java/lang/Object
#5 = Utf8 m
#6 = Utf8 I
#7 = Utf8
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 inc
#12 = Utf8 ()I
#13 = Utf8 SourceFile
#14 = Utf8 Foo.java
#15 = NameAndType #7:#8 // "":()V
#16 = NameAndType #5:#6 // m:I
#17 = Utf8 com/vonzhou/learn/jvm/klass/Foo
#18 = Utf8 java/lang/Object
{
public com.vonzhou.learn.jvm.klass.Foo();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
LineNumberTable:
line 3: 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 7: 0
}
SourceFile: "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方法的属性的解释)