每一个class字节码文件都唯一对应一个类或接口,class文件中记录中类或接口的基本信息,但反之不成立,不是每一个类或接口都有一个唯一对应的字节码文件,首先类或接口的字节码可以不以文件的方式存储,可以直接从内存中生成字节码,而不产生.class文件,动态代理的原理就是直接内存中生成字节码流,根据加载字节码流进行类加载操作,类实例化,生成代理对象。
字节码文件记录的信息:魔术,class文件主次版本,常量池数量及常量池表,类或接口的访问标志,类索引,超类索引,接口数量及接口表,字段数量及字段表,方法数量及方法表,属性属性及属性表
魔术:四个字节,用于定义此字节码文件是否符合虚拟机规范,保证字节码文件不会威胁虚拟机的安全,若为cafebabe则表示字节码符合虚拟机规范
主次版本号:四个字节,前两字节表示次版本号,后两字节表示主版本号,用于定义编译的字节码文件格式版本,第版本虚拟机拒绝运行高版本字节码文件,但高版本虚拟机会向下兼容低版本字节码文件
类索引及父类索引:四个字节,用于存储指向常量池constant_class_info对应的有效索引,而constant_class_info存储常量池列表的constant_utf8_info常量项索引,根据此索引可找到类和父类的全限定名
接口数量及接口表:接口属性用于存储当前类或接口的直接超类接口数量,接口表是一个数组,记住,只有常量池表从1开始计数,其余都是从数组下表0开始计数,接口表数组的每一个数组元素存储此类或接口的直接超类接口的有效索引,根据此索引找到constant_class_info对应的常量项,根据constant_class_info可找到对应直接超类接口的全限定名
字段数量及字段表:字段数量用于存储类或接口的字段数目,包括类字段和实例字段,字段表为一个数组,每一个数组元素都相当于一个field_info结构的对象,field_info结构包含字段完整信息:字段标识符,字段访问修饰符,字段是类字段还是实例字段,字段是否为常量等,注意:此处字段表示当前类或接口的字段,不包括从超类或接口继承的字段,java语法规范不允许同一个类或接口中出现同一字段名的不同字段,但是class文件中却可以允许出现相同字段名的不同字段,只有字段的描述符不同即可,field_info结构属性:access_flags用于存储字段的访问标志,acc_private,acc_protected,acc_public,acc_final,acc_static,acc_volatile等,注意:acc_final与acc_volatile不能同时出现在同一字段,name_index指向常量池constant_utf8_info常量项的有效索引,获取当前字段的简单名称,descriptor_index指向常量池constant_utf8_info常量项的有效索引,获取当前字段的描述符,attribute_count,attributes[attributes_count]这两项表示字段的属性信息,用于描述字段相关信息,attribute数组每一个元素都是一个attribute_info结构的元素
方法数量及方法表:方法数量用于存储当前类或接口的方法数目,包括实例方法,类方法,抽象方法,方法表是一个数组,每一个数组元素都是一个method_info结构,method_info结构包含方法的完整信息:方法描述符,访问修饰符,是否为final方法,是否为abstract方法等,注意:此处的方法数组只是表示当前类或接口的所有方法,并不包括从超类及父接口继承来的方法,java语法规范java类或接口中不允许出现方法签名完全一样的方法同时出现,会编译报错,而字节码层面却允许方法签名完全相同的方法同时出现,只需要保证方法的返回值类型不同,method_info结构属性与field_info一致,但acc_flags类型不尽相同,注意acc_abstract不能与acc_final,acc_static,acc_private,acc_synchronized,acc_native同时使用,接口方法中只能使用acc_public,acc_abstract,此处我有一个疑问,接口中default方法有没有对应的访问标志,注意:<init>方法只能使用acc_private,acc_protected,acc_public访问标志