class文件&dex文件
class文件结构与解析
文件结构
-
一种8位字节的二进制流文件
-
各个数据按顺序紧密排序,无间隙
这样做的好处就是可以减少class文件的体积,提高JVM加载class文件效率
-
每个类或接口都单独占据一个class文件
这样就可以做到每个类或接口都可以独立管理自身的内容,无需相互交叉
class文件中的各个数据项
-
magic
无符号4字节,用来表示class文件的开头,加密段,给虚拟机用来判断当前的 class文件是否被串改过
-
minor_version class文件最小可以被哪个版本的jdk所加载,也就是最小适配的jdk
-
major_version 表示我们当前class文件是由哪个版本的jdk生成的
-
constant_pool_count class文件中常量池的数量,通常只有一个常量池
-
constant_pool 代表常量池,类型为cp_info(结构体类型), 常量池中主要包含的内容:
- CONSTANT_Integer_info:存储class文件中的int类型
- CONSTANT_Long_info:存储class文件中的long类型
- CONSTANT_String_info:存储class文件中的string类型, 它们分别存储字节码中的int、long、string类型,当然还有CONSTANT_Short_info、CONSTANT_Float_info等
- CONSTANT_Class_info:记录类中相关的信息、不仅记录了当前类的信息,还记录了引用到的一些类的信息
- CONSTANT_Fieldref_info:记录类中Field相关的信息
- CONSTANT_Methodref_info:记录类中Method相关的信息 Ps:这三个里面存储的并不是真正的内容,都是一些索引,这些索引指向的又是CONSTANT_String_info等<
-
access_flags 表示class文件的作用域标志
access_flags的取值范围和相应含义
-
ACC_PUBLIC:取值为0x0001
-
ACC_FINAL::取值为0x0010
-
ACC_SUPER:取值为0x0020,用于确定该Class文件里面的invokespecial指令使用的是哪一种执行语义。目前Java虚拟机的编译器都应当设置这个标志。ACC_SUPER标记是为了向后兼容旧编译器编译的Class文件而存在的,在JDK1.0.2版本以前的编译器产生的Class文件中,access_flag里面没有ACC_SUPER标志。同时,JDK1.0.2前的Java虚拟机遇到ACC_SUPER标记会自动忽略它
-
ACC_INTERFACE:取值为0x0200,表示是接口
-
ACC_ABSTRACT:取值为0x0400
-
ACC_SYNTHETIC:取值为0x1000, 表示并非Java源码生成的字节码
-
ACC_ANOTATION:0x2000,表示是注解
-
ACC_ENUM:取值为0x4000,表示是枚举
-
-
this_class this_class是指向constant pool的索引值,该值必须是CONSTANT_Class_info类型,指定当前字节码定义的类或接口。
-
super_class super_class是指向constant pool的索引值,该值必须是CONSTANT_Class_info类型,指定当前字节码定义的类或接口的直接父类。只有Object类才没有直接父类,此时该索引值为0。并且父类不能是final类型。接口的父类都是Object类。
-
interfaces_count 当前class文件直接实现的接口数量。
-
interfaces 当前class文件直接实现的接口,只记录直接实现的,不会记录间接实现的。
-
fields_count class文件中成员变量的数量。
-
fields class文件中所有的成员变量,field_info类型的结构体,该结构体中主要包含了每个成员变量的name、所属的类以及类型。
-
methods_count 记录class文件中方法的数量。
-
methods 记录class文件中所有的方法,类型为method_info结构体类型,主要包含了方法的名字、类型、access_flags等信息。
-
attribute_count 记录了class文件属性的数量。
-
attributes 记录class文件的一些属性,除去上面的一些信息剩下的都包含在attributes中,比如 说注解。
class文件弊端
- 内存占用大,不适合移动端
- 堆栈的加栈模式,加载速度慢
- 文件IO操作多,类查找慢
dex文件结构与解析
文件结构
- 一种8位字节的二进制流文件
- 各个数据按顺序紧密的排列,无间隙
- 整个应用中所有Java源文件都放在一个dex中
文件头
-
header
记录dex文件的信息,以及所有字段大致的分布
索引区
-
string_ids
字符串数据索引,记录了整个应用中所有的字符串,包括构造方法的字符串,类名字符串,用到的变量和方法的字符串
-
type_ids
类似数据索引,记录了每个类型的字符串索引
-
proto_ids
原型数据索引,记录了方法声明的字符串,返回类型字符串,参数列表
-
field_ids
字段数据索引,记录了所属类,类型以及方法名
-
method_ids
类方法索引,记录方法所属类名,方法声明以及方法名等信息
数据区
-
class_defs
类定义数据索引,记录指定类各类信息,包括接口,超类,类数据偏移量
-
data
数据区,保存了各个类的真实数据,也就是上面索引区指向的地方,通过索引到数据区就可以找到真实的值
-
link_data
连接数据区,就是连接动态链接库so库的指向
对比与总结
从宏观上两种字节码文件是一样的,都是二进制无缝隙的文件格式,但是.class文件就是单独的结构体,因此存在许多的多余的信息,而.dex就划分成三个区,这三个区直接存储了整个project中所有源文件,所以当源文件越来越多的时候,.dex可以复用的地方就变多了,极大地减少.dex文件的体积,从而也提高了效率。
参考资料:
- https://www.jianshu.com/p/5f9a989d3082
- https://www.jianshu.com/p/f7f0a712ddfe