类文件结构 读书笔记

时间:2021-05-17 14:03:50
    Java虚拟机不与包含Java在内的任何语言绑定,只和Class文件这种二进制文件格式关联。
        Class文件包含了Java虚拟机指令集和符号表以及其他辅助信息。
    1.Class文件结构
        任何一个Class文件都对应着唯一一个类或接口的定义信息。
        Class文件是以8位字节为基础的二进制流,数据按照顺序紧密排列在Class文件中,中间没有任何分隔符。
            遇到需要占用8字节以上空间的数据项时,会按照高位在前的方式分成若干个8位字节进行存储
                最高位字节在地址最低位,最低位字节在地址最高位(Big-Endian)
        Class文件采用蕾西C语言结构体的结构来存储数据,其中有两种类型:
                1.无符号数
                        u1、u2、u4、u8代表1、2、4、8个字节的符号引用
                2.表
                        由无符号数或者其他表构成的,整个Class文件本质上是一张表
                   
    2.各个数据项
            1.魔数 -----Class文件前四个字节
                唯一作用是确定文件是否为一个被虚拟机接受的Class文件。
                    一些文件比如jpeg或者gif文件头中使用魔数,是基于安全方面考虑,因为文件扩展名可以随意改动。
            2.版本号----魔数后的四个字节
                    第5、6个字节是次版本号(Minor Version),第7、8个字节是主版本号(Major Version)
                        高版本JDK能向下兼容低版本Classs文件,低版本不能运行高版本Class文件
            3.常量池  使用javap命令可以计算出常量池
                   1. 常量池入口放置u2类型数据(常量池容量计数值)----该计数值从1开始计数,第0项给不引用任何常量池项目的索引数据
                   2.常量池存放两大类常量:
                            1.字面量   
                                类似常量(文本字符串、声明为final的常量值等)                 
                            2.符号引用
                                1.类和接口的全限定名
                                2.字段的名称和描述符
                                3.方法的名称和描述符
 
                    3.常量池中每一项常量都是一个表
                            表结构的共同特点:表开始的第一位是u1类型的标志位(tag),代表该常量属于哪种常量类型
                                例如:标志位为0x07,查表可知常量属于CONSTANT_Class_info类型,代表一个类或者接口的符号引用。
                                        CONSTANT_Class_info的结构为
 
类型 名称 数量
u1 tag 1
u2 name_index 1
                                                    tag是标志位,name_index为索引值,这个索引值指向常量池中 CONSTANT_Utf8_info类型常量, CONSTANT_Utf8_info代表类或者接口的全限定名
                                          查name_index值为0x0002,指向常量池第二项,第二项标志位为0x01,也就是一个 CONSTANT_Utf8_info常量
                                             CONSTANT_Utf8_info类型        
类型 名称 数量
u1 tag 1
u2 length 1
u1 bytes length
                                                length为UTF-8编码字符串字节数,后面跟着length长度的数据为UTF-8缩略编码格式的字符串。
                                                            UTF-8缩略编码和普通UTF-8编码区别:
                                                                        从'\u0001'到'\u007f'之间字符缩略编码用一个字节表示。
                                                                        从'\u0080'到'\u07ff'之间字符缩略编码用两个字符表示。
                                                                        从'\u0800'到'\uffff'之间字符缩略用普通UTF-8编码规则三个字符表示。
                                                                        
                                                            Class文件中所有的方法、字段都用 CONSTANT_Utf8_info型常量描述, CONSTANT_Utf8_info中最大长度就是Class文件中方法、字段     
                                                      名的最大长度,最大长度即length的值,length用两个字节表示,即方法、字段名超过64KB就无法编译。
 
                                                            
            4.访问标志(access_flags)
                    常量池结束后,是访问标志,用来识别类或接口层次的访问信息。
                            Class是类还是接口、是否定义为public类型、是否定义为abstarct类型;若为类是否被声明为final
                    access_flags一共有16个标志位可用,没有使用到的标志位要求一律为0。
                    access_flags的标志为所有标志位的或(|)运算的和
                         例:普通Java类,则ACC_PUBLIC,ACC_SUPER为真,ACC_FINAL、ACC_INTERFACE ACC_ABSTRACT ACC_SYNTHETIC ACC_ANNOTATION ACC_ENUM为  
                    假
            5.类索引、父类索引、接口索引集合
                    类的继承关系由三项数据组成:
                        类索引:确定类的全限定名
                        父类索引:确定类的父类的全限定名
                                除了java.lang.Object,所有的父类索引都不为0(因为除了java.lang.Object所有的类都有父类)
                        接口索引集合:描述类实现了哪些接口
                    
                    类索引、父类索引、接口索引集合按顺序排列在访问标志之后。
                           类索引和父类索引用两个u2类型的索引值表示,各自指向CANSTANT_Class_info的描述符常量,通过CANSTANT_Class_info的常量中的索引值找到定义在
                    CANSTANT_Utf8_info类型的全限定名字符串      
                            接口索引集合:入口第一项----u2类型的接口计数器,表示索引表的容量,如果该类没有实现任何接口,则计数器为0   
            6.字段表集合
                    描述接口或者类中声明的变量。字段包含类级变量以及实例级变量,不包括方法内部声明的变量。
                        字段包含信息:作用域(private、protected、public),实例变量还是类变量(static修饰),可变性(final),并发可见性(volatile),是否可序列化
                    (transient)
                    修饰符存在与否可以使用布尔值来表示,就可以用标志位来标识。字段名称、字段数据类型用常量池中常量表示。 
                    
                    全限定名:类名中"."换成"/",名称结尾用";"隔开
                    简单名称:没有类型和参数修饰的方法或者字段名称
                    描述符:描述字段的数据类型、方法、返回值。
                        基本数据类型用大写字母表示,对象类型用L加全限定名表示
                        数组类型加"["
                        参数先参数列表,后返回值,如void类型"()V",java.lang.String.toString()描述符为"()Ljava/lang/String"
            7.方法表集合
                    方法表结构和字段表类似,包括访问标志、名称索引、描述索引和属性表集合。
                    方法里面的代码经过编译生成字节码指令后,放入属性表中"Code"属性中
 
 
                8.属性表集合
                        Class文件、字段表、属性表都可以携带属性表集合。