本文通过分析一个简单java类文件的字节码,希望借此能快速了解java类文件格式
为了分析字节码,必须有一个整体的格式如下:
以上面的表作为分析的基础,开始行动!
一段简单的java代码
1
2
3
4
5
6
7
8
9
|
package org.kaka.clazz;
public class TestClass {
private int m;
public int inc(){
return m+1;
}
}
|
查看字节码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
00000000 ca fe ba be 00 00 00 32 00 13 0a 00 04 00 0f 09 |.......2........|
00000010 00 03 00 10 07 00 11 07 00 12 01 00 01 6d 01 00 |.............m..|
00000020 01 49 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29 |.I...<init>...()|
00000030 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e |V...Code...LineN|
00000040 75 6d 62 65 72 54 61 62 6c 65 01 00 03 69 6e 63 |umberTable...inc|
00000050 01 00 03 28 29 49 01 00 0a 53 6f 75 72 63 65 46 |...()I...SourceF|
00000060 69 6c 65 01 00 0e 54 65 73 74 43 6c 61 73 73 2e |ile...TestClass.|
00000070 6a 61 76 61 0c 00 07 00 08 0c 00 05 00 06 01 00 |java............|
00000080 18 6f 72 67 2f 6b 61 6b 61 2f 63 6c 61 7a 7a 2f |.org/kaka/clazz/|
00000090 54 65 73 74 43 6c 61 73 73 01 00 10 6a 61 76 61 |TestClass...java|
000000a0 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 00 21 00 03 |/lang/Object.!..|
000000b0 00 04 00 00 00 01 00 02 00 05 00 06 00 00 00 02 |................|
000000c0 00 01 00 07 00 08 00 01 00 09 00 00 00 1d 00 01 |................|
000000d0 00 01 00 00 00 05 2a b7 00 01 b1 00 00 00 01 00 |......*.........|
000000e0 0a 00 00 00 06 00 01 00 00 00 03 00 01 00 0b 00 |................|
000000f0 0c 00 01 00 09 00 00 00 1f 00 02 00 01 00 00 00 |................|
00000100 07 2a b4 00 02 04 60 ac 00 00 00 01 00 0a 00 00 |.*....`.........|
00000110 00 06 00 01 00 00 00 07 00 01 00 0d 00 00 00 02 |................|
00000120 00 0e |..|
00000122
|
step1)javamagicnumber
step2)javaversion
step3)常量池
接下来是描述常量表的长度0x0013,一共是(19-1)项,人肉分析如下
第1项
tag:0x0a,CONSTANT_Methodref_info即方法声明
index:0x0004,指向常量池中CONSTANT_Class_info,见常量池第4项
index:0x000f,指向常量池中CONSTANT_NameAndType_info见常量池第15项
第2项
tag0x09,CONSTANT_Fieldref_info即字段声明
index:0x0003,指向常量池中CONSTANT_Class_info,见常量池第3项
index:0x0010,指向常量池中CONSTANT_NameAndType_info见常量池第16项
第3项
tag:0x07,CONSTANT_Class_info即类声明
index:0x0011,指向常量池中的CONSTANT_Utf8_info,第17项
第4项
tag:0x07,CONSTANT_Class_info即类声明
index:0x0012,指向常量池中的CONSTANT_Utf8_info,第18项
第5项
第6项
第7项
tag:0x01,CONSTANT_Utf8_info即字符串说明
length:0x0006,长度为6个字节
bytes:0x3c696e69743e,内容为"<init>"
第8项
第9项
第10项
第11项
第12项
第13项
第14项
第15项
tag:0x0c,CONSTANT_NameAndType_info即字段或者方法说明
index:0x0007,字段或者方法常量索引,见常量池第7项
index:0x0008,字段或者方法常量索引,见常量池第8项
第16项
tag:0x0c,CONSTANT_NameAndType_info即字段或者方法说明
index:0x0005,字段或者方法常量索引,见常量池第5项
index:0x0006,字段或者方法常量索引,见常量池第6项
第17项
tag:0x01,CONSTANT_Utf8_info即字符串说明
length:0x0018,长度为24个字节
bytes:0x6f72672f6b616b612f636c617a7a2f54657374436c617373内容为"org/kaka/clazz/TestClass"
第18项
可以看出
CONSTANT_Methodref_info、CONSTANT_Fieldref_info都依赖于CONSTANT_Class_info、CONSTANT_NameAndType_info
CONSTANT_Class_info依赖于CONSTANT_Utf8_info,后者用于声明类的名字
CONSTANT_NameAndType_info依赖于两个CONSTANT_Utf8_info
列举常量池结构
可以对比下javap的结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
Compiled from "TestClass.java"
public class org.kaka.clazz.TestClass extends java.lang.Object
SourceFile: "TestClass.java"
minor version: 0
major version: 50
Constant pool:
const #1 = Method #4.#15; // java/lang/Object."<init>":()V
const #2 = Field #3.#16; // org/kaka/clazz/TestClass.m:I
const #3 = class #17; // org/kaka/clazz/TestClass
const #4 = class #18; // java/lang/Object
const #5 = Asciz m;
const #6 = Asciz I;
const #7 = Asciz <init>;
const #8 = Asciz ()V;
const #9 = Asciz Code;
const #10 = Asciz LineNumberTable;
const #11 = Asciz inc;
const #12 = Asciz ()I;
const #13 = Asciz SourceFile;
const #14 = Asciz TestClass.java;
const #15 = NameAndType #7:#8;// "<init>":()V
const #16 = NameAndType #5:#6;// m:I
const #17 = Asciz org/kaka/clazz/TestClass;
const #18 = Asciz java/lang/Object;
{
public org.kaka.clazz.TestClass();
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
public int inc();
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
}
|
两者是一致的
step4)访问标志
接下来的两个字节0x0021是由下标中的0x0001|0x0020计算出来的,表类是public的,且是jdk1.2以后的编译器编译出来的
访问标志
标志名称 |
标志值 |
含义 |
ACC_PUBLIC |
0x0001 |
是否为public类型 |
ACC_FINAL |
0x0010 |
是否被声明为final,只有类可以设置,接口不能设置该标志 |
ACC_SUPER |
0x0020 |
是否允许使用invokespecial字节码指令(查了一下该命令的作用为"调用超类的构造
方法,实例的构造方法,私有方法"),JDK1.2以后的编译器编译出来的class文件
该标志都为真
|
ACC_INTERFACE |
0x0200 |
标识这是一个接口 |
ACC_ABSTRACT |
0x0400 |
是否被声明为abstract类型,对于接口和抽象类来说此标志
为真,其他类为假
|
ACC_SYNTHETIC |
0x1000 |
标识这个类并非由用户代码生成 |
ACC_ANNOTATION |
0x2000 |
标识这是一个注解 |
ACC_ENUM |
0x4000 |
标识这是一个枚举 |
step5)类信息
头两个字节0x0003,指向常量池中的第3项,即类名
接下来的两个字节0x0004指向常量池中的第4项,即父类名
接下来的两个字节0x0000表示类实现的接口的个数,本例子中为0,如果有的n个话,后面还会有2n个字节的常量池索引
step6)字段信息
头两个字节0x0001字段的个数,本例中为1
接下来就是1个field_info结构
头两个字节0x0002表示accss_flags,即private
接下来0x0005表示字段名,指向常量池的第5项,即本例中"m"
接下来的0x0006表示字段的描述信息,指向常量池的第6项,即本例中"I",表示是int类型
接下来的0x0000表示字段的属性信息(用于扩展或者补充说明字段信息)的个数,本例中为0,如果有n个的话,后面还会有n个attribute_info结构
step7)方法信息
step8)属性信息
头两个字节为0x0001,表示有一个属性
接下是1个attribute_info结构
0x000d表示属性名,指向常量池的第13项,即SourceFile,表示类的源文件
0x00000002,属性长度,即接下来的字节个数
0x000e表示源文件名,指向常量池的第14项,即"TestClass.java"
小结
分享到:
相关推荐
class文件解析器class文件解析器class文件解析器
一个解析java class文件的代码
最近在拜读《深入理解java虚拟机》,根据书上的步骤来解析class文件,并提供了对应的样例数据分析,利于读者阅读
java语言实现的class文件解析,让你明白class文件中到底都有些什么东西。
基于Go的Java Class文件解析工具
NULL 博文链接:https://chenjingbo.iteye.com/blog/1769645
NULL 博文链接:https://bernoulli.iteye.com/blog/1768713
分析记录了class文件内部的文件结构以及分析过程,上传到CSDN当一个记录用,有问题不要喷呀,一起学习进步
MingClass文件解析器关于对Java编译后的Class文件进行解析版本(更新说明)0.1.0修复读取Double和Long类型时出现找不到指定类型的错误移除jdk9的方法InputStream#readAllBytes(),替换为Files#readAllBytes(),以支持...
class文件变java源代码,可同时打开多个文件,关键字高亮显示
Jvm之用C#解析class文件
python实现的简单的class解析以及简单执行class,使用python2解析java class文件,并简单执行 class,让大家更加了解class
用go语言写的java虚拟机,主要是清楚的表达了jvm的原理。不懂go语言的其实也没关系,其中classpy这个可执行的jar文件,可以清楚的展现出class文件的结构
java Class文件分析及其解析执行是分析JVM的重要部分,通过实例对Class文件的结构进行了详细分析,并初步实现了Class文件的解析执行。
Java 代码解析 class 文件