java class 文件格式分析及实例完全标注
2017-10-11 11:34
471 查看
1. java class 文件格式,(理论部分)
java class 是从源码经编译而生成, 其信息是对源码的变换.可以用如下结构来描述, 我们看到,它非常简洁! 本贴就是来解释这个ClassFile 结构!
ClassFile {
u4 magic; // 4byte 0xCAFEBABE
u2 minor_version;
u2 major_version; //主次版本号合起来4byte, 大端序.
u2 constant_pool_count; // 常量池个数
cp_info constant_pool[constant_pool_count-1]; //从1开始到常量池, 序号0不使用.
u2 access_flags; //访问标志
u2 this_class; //本类的类名引用
u2 super_class; //父类的类名引用
u2 interfaces_count; //接口个数
u2 interfaces[interfaces_count]; //接口表,每一个项必须指向常量池中Class类型常量
u2 fields_count; //字段个数
field_info fields[fields_count]; //字段表,每一个项是field_info类型常量
u2 methods_count; //方法个数
method_info methods[methods_count]; //方法表,每一个项是method_info类型常量
u2 attributes_count; //属性个数
attribute_info attributes[attributes_count];//属性表,每一个项是attribute_info类型常量
}
其中u1、u2、u4分别代表1、2、4个字节无符号数。
1.1 基本信息见类定义中的注释
1.2 常量池的概念可参考:
1.3 class 文件的访问标志 access_flags,(2bytes)
有的bit 位没有定义
标志名 标志值 标志含义 设置者
ACC_PUBLIC 0x0001 public类型 类或接口
ACC_SUPER 0x0020
使用新的invokespecial语义 类或接口
ACC_INTERFACE 0x0200 接口类型 接口
ACC_SYNTHETIC 0x1000 该类不由用户代码生成
ACC_ANNOTATION 0x2000 注解类型
ACC_ENUM 0x4000 枚举类型
1.4 本类类名,父类类名容易理解
接口个数及接口表也容易理解,只是一个名称引用.
下面介绍后面几个重要概念,字段表,方法表,属性表
1. 字段表的概念
字段表由字段构成, 字段如下定义:class field_info
{
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
};
1.1 字段的访问标志 access_flags (2bytes)
标志位名称 值 含义 设定者
ACC_PUBLIC 0x0001 字段被设为public 类或接口
ACC_PRIVATE 0x0002 字段被设为private 类
ACC_PROTECTED 0x0004 字段被设为protected 类
ACC_STATIC 0x0008 字段被设为static 类或接口
ACC_FINAL 0x0010 字段被设为final 类或接口
ACC_VOLATILE 0x0040 字段被设为volatile 类
ACC_TRANSIENT 0x0080 字段被设为transient 类
1.2 name_index 显然是一个名字的索引
1.3 descriptor_index, 显然还是一个字符串索引
1.4 后面是属性描述.
属性通常指这是代码, 这是文件名等的指示,就后面实例.
2. 方法表的概念
方法表由方法构成, 方法信息如下定义:Class method_info
{
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
2.1 方法的访问标志 access_flags (2bytes)
ACC_PUBLIC 0x0001 方法设为public 类或接口
ACC_PRIVATE 0x0002 方法设为private 类
ACC_PROTECTED 0x0004 方法设为protected 类
ACC_STATIC 0x0008 方法设为static 类
ACC_FINAL 0x0010 方法设为final 类
ACC_SYNCHRONIZED 0x0020 方法设为sychronized 类
ACC_NATIVE 0x0100 方法设为native 类
ACC_ABSTRACT 0x0400 方法设为abstract 类或接口
ACC_STRICT 0x0800 方法设为strictFP 类或接口的方法
3. 属性表的概念
属性表由属性构成, 属性信息如下定义:在字段或方法的定义中也可以有属性, 例如代码属性,代码长度等.
attribute_info
{
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
方法表中的方法,字段表中的字段,如果被访问过, 会被保存到常量池中,
可见这些信息还是有些冗余的, 但方法表中方法包括了代码内容属性,
字段表中的字段也可以包含其它属性, 可扩充性还是考虑到了.
2. java class 文件格式举例:
2.1 源码
$ cat hello.java public class hello { String str = ""; public String getStr() { return str; } public void setStr(String str) { this.str = str; } }
2.2 编译
javac hello.java2.3 查看其二进制代码
xxd hello.class > hello.class.xxd2.4 对二进制代码进行标注
对照javap -v hello.class , 并结合ClassFile 定义来分析0000000: cafe babe 0000 0033 0017 0a00 0500 1208 .......3........ 头部信息 cafebabe -> magic, 00000033 -> 版本 头部信息后跟常量池 0017 -> 常量池项个数0x17-1个(实际是1-0x16), 第一项 { 0a ->tag : //Methodref tag 0005 -> class_index ://java/lang/Object 0012 -> name_and_type_index :// "<init>":()V } 第二项 { 08 ->tag : //String tag 0013 -> string_index ://为空字符串 } 依次可以分析之0x16个常量. 对常量的理解,可以参考[java 中的常量池概念附实例](http://blog.csdn.net/hejinjing_tom_com/article/details/78190783)... 0000010: 0013 0900 0400 1407 0015 0700 1601 0003 ................ 0000020: 7374 7201 0012 4c6a 6176 612f 6c61 6e67 str...Ljava/lang 0000030: 2f53 7472 696e 673b 0100 063c 696e 6974 /String;...<init 0000040: 3e01 0003 2829 5601 0004 436f 6465 0100 >...()V...Code.. 0000050: 0f4c 696e 654e 756d 6265 7254 6162 6c65 .LineNumberTable 0000060: 0100 0667 6574 5374 7201 0014 2829 4c6a ...getStr...()Lj 0000070: 6176 612f 6c61 6e67 2f53 7472 696e 673b ava/lang/String; 0000080: 0100 0673 6574 5374 7201 0015 284c 6a61 ...setStr...(Lja 0000090: 7661 2f6c 616e 672f 5374 7269 6e67 3b29 va/lang/String;) 00000a0: 5601 000a 536f 7572 6365 4669 6c65 0100 V...SourceFile.. 00000b0: 0a68 656c 6c6f 2e6a 6176 610c 0008 0009 .hello.java..... 00000c0: 0100 000c 0006 0007 0100 0568 656c 6c6f ...........hello 00000d0: 0100 106a 6176 612f 6c61 6e67 2f4f 626a ...java/lang/Obj 00000e0: 6563 7400 2100 0400 0500 0000 0100 0000 ect.!........... 常量池结束后,跟类描述 0021 -> access_flags. // ACC_PUBLIC, ACC_SUPER 0004 -> this_class //hello 0005 -> supper_class //java/lang/Object 类描述后跟接口表 0000 -> interfaces_count// 接口个数0个 接口表结束后,跟字段表 0001 -> field_count // 字段个数1个 如下: 第一个字段 { 0000 -> access_flags 0006 -> name_index : //str 0007 -> descriptor_index : //Ljava/lang/String; 0000 -> attributes_count : //null } 说明只定义了一个字段 String str; 00000f0: 0600 0700 0000 0300 0100 0800 0900 0100 ................ 字段表结束后,跟方法表 0003 -> methods_count //方法个数3个, 如下: 第一个方法 { 0001 -> access_flags : //ACC_PUBLIC 0008 -> name_index : //<init> 默认初始化方法 0009 ->descriptor_index: //()V, 无参void 返回值 0001 -> 有一个属性, 属性内容如下: { 000a -> attribute_name_index : //Code,属性名称是代码 00000027->length : //代码长度为0x27 bytes 后面的0x27bytes 代码 } } 0000100: 0a00 0000 2700 0200 0100 0000 0b2a b700 ....'........*.. 0000110: 012a 1202 b500 03b1 0000 0001 000b 0000 .*.............. 0000120: 000a 0002 0000 0001 0004 0003 0001 000c ................ 第二个方法 { 0001 -> access_flags : //ACC_PUBLIC 000c -> name_index : //getStr 000d ->descriptor_index: //()Ljava/lang/String; 无参String引用返回 0001 -> 有一个属性,属性内容如下: { 000a -> attribute_name_index : //Code, 属性名称是代码 0000001d -> length : //代码长度为0x1d bytes 后面的0x1dbytes 代码 } } 0000130: 000d 0001 000a 0000 001d 0001 0001 0000 ................ 0000140: 0005 2ab4 0003 b000 0000 0100 0b00 0000 ..*............. 0000150: 0600 0100 0000 0700 0100 0e00 0f00 0100 ................ 第三个方法 { 0001 -> access_flags : //ACC_PUBLIC 000e -> name_index : //setStr 000f ->descriptor_index: //(Ljava/lang/String;)V, String引用参数无返回值 0001 -> 有一个属性,属性内容如下: { 000a -> attribute_name_index : //Code, 属性名称是代码 00000022 -> length : //代码长度为0x22 bytes 后面的0x22bytes 代码 } } 0000160: 0a00 0000 2200 0200 0200 0000 062a 2bb5 ...."........*+. 0000170: 0003 b100 0000 0100 0b00 0000 0a00 0200 ................ 0000180: 0000 0c00 0500 0d00 0100 1000 0000 0200 ................ 方法表结束后,后面跟属性表 0001 -> attributes_count //属性个数1个, 如下: { 0010 -> attribute_name_index : //SourceFile 0000 -> descriptor_index : //无描述信息 0002 -> length : //长度2bytes 0011 : //这实际上是字符串索引值, hello.java } 0000190: 11 .
相关文章推荐
- Java Class文件结构解析 及 实例分析验证
- java的class文件格式分析
- 实例分析Java Class的文件结构
- 实例解析Java class文件格式
- 实例分析Java class文件内容
- 实例分析Java Class的文件结构
- 实例分析Java Class的文件结构
- 实例分析Java Class的文件结构
- 实例分析Java Class的文件结构
- 实例分析 Java Class 的文件结构
- 实例分析Java Class的文件结构
- Java Class文件格式解析及实例
- 实例分析Java Class的文件结构
- 实例分析Java Class的文件结构
- 实例分析Java Class的文件结构
- 通过阅读、分析和翻译二进制格式的Java Class文件学习Java Class的技术
- 实例分析Java Class的文件结构
- 深入java虚拟机--Class文件实例解析
- class文件格式分析---class文件结构
- 解析Java的Class文件格式——解析魔…