[一]class 文件浅析 .class文件格式详解 字段方…
2018-09-01 05:39:18来源:博客园 阅读 ()
前言概述
class文件包含了java虚拟机指令集 和 符号表 以及若干其他辅助信息.
class文件是一组以8位字节为基础单位的二进制字节流
各个数据项按照顺序紧凑的排列在Class文件中,中间没有任何分隔符号
class文件采用类似 c结构体的格式存储数据
数据类型只有两种
无符号数 和 类c结构体的 表 表是由无符号数或者其他的表构成的
整个class文件就是一张表
无论无符号数还是表,当需要描述同一类型但数量不定的多个数据时,经常会使用一个前置的容量计数器用于指示接下来的数据个数,然后是若干个连续的数据项
class文件主要内容为: 类本身的信息 字段 方法 常量池 以及方法中的Code属性 再就是一些相关的辅助信息
类本身的信息类本身有一些必备的描述信息,比如类名 访问修饰符 继承关系等
字段用于描述接口或者类中声明的变量
字段包括类变量以及实例变量,不包括局部变量 他有访问标志 名称 描述符信息
方法用于描述方法表信息 类似字段 也有访问标志 名称 描述符信息
常量池可以理解为Class文件的资源仓库,所以他是与其他项目关联最多的数据类型
主要是两大类: 字面量 以及符号引用
字面量接近java语言层面的常量概念 比如文本字符串 声明为final常量的值
符号引用包括:
类和接口的全限定名
字段的名称和描述符
方法的名称和描述符
虚拟机加载class文件的时候动态链接,所以class文件中不会保存方法的最终内存布局, 还需要转换
虚拟机运行时从常量池中获得对应的符号引用,然后在创建或者运行时解析翻译到具体的内存地址中
Code属性存放的Java方法的内容,位于方法method_info 内
存放的是java方法经过编译器编译成的字节码指令 说白了存放的就是代码的编译后形式
概述:
class文件作为JVM的"机器语言" 主要包括两部分的信息,基础信息以及附加信息
基础信息为源代码中呈现的信息
类自身信息/字段/方法用于描述源代码中的类/字段/方法
常量池中保存了资源信息,比如字段的名字 方法的描述符等
方法中的code属性保存了方法中的代码的执行逻辑
额外信息为虚拟机执行过程中或者字节码指令执行所需要的信息
为了保证虚拟机能够正确的加载class文件
另外虚拟机加载类还需要做一些额外的工作比如校验信息等
字节码指令的执行可能还需要一些额外的信息
这些额外的信息通常也是保存在常量池中或者以属性的形式出现
|
class文件的数据格式了解
struct 结构体名
{
类型名1 成员名1;
类型名2 成员名2;
.....
类型名n 成员名n;
};
|
struct student { char name[10]; char sex; int age; float score; };
class文件中的数据类型
ps: 所谓大小端 |
cp_info{
u1 tag;
u1 info[ ]
}
class文件的形式是一张巨大的表,是一个二进制字节流
只有两种数据表示形式 无符号数 以及 表(结构体 复合的数据结构)
各个数据项严格的按照顺序存放,之间没有填充或者对齐,这也是为何编译后代码如此紧凑的原因之一
基本数据类型为: u1 u2 u4 u8
|
class文件的数据组织格式解读
ClassFile { u4 magic; u2 minor_version; u2 major_version; u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1]; u2 access_flags; u2 this_class; u2 super_class; u2 interfaces_count; u2 interfaces[interfaces_count]; u2 fields_count; field_info fields[fields_count]; u2 methods_count; method_info methods[methods_count]; u2 attributes_count; attribute_info attributes[attributes_count]; }
public class HelloWorld { private int x; private String y; public void fun() { } public static void main(String[] args) { System.out.println("hello world"); } }
第一项 u4 magic
复合class文件魔数设置0xCAFEBABE
|
第二项 u2 minor_version 第三项 u2 major_version 所以说 主版本号为 52(34是十六进制) 次版本号为0 与javap解析后的数据吻合 |
第四项 u2 constant_pool_count 十六机制27 十进制39 可以看到javap解析后的Constant pool:中总共有从#1 到 #38 常量池计数器constant_pool_count的值等于常量表中的成员数加1 常量池标的索引值只有大于0 且小于constant_pool_count时才有效 所以此处解析也是对的 |
第五项 cp_info constant_pool[constant_pool_count-1] 他是常量池 常量池表中的所有项目的格式为 cp_info{ u1 tag; u1 info[];
具体形式由tag的值决定 因为常量池计数为39 常量池中个数为[constant_pool_count-1]所以是38 也就是接下来会有38个 {u1 和 多个u1 } 这种形式的数据组合 第一个tag tag = 7 表示 CONSTNT_Class 结构为 CONSTANT_Class_info{ u1 tag; u2 name_index;
name_index 的值是常量池中的一个索引 他指向的是2号索引 也就是 在接下来的一个u1 是下一个常量池数据项的tag tag 为1 表示CONSTANT_Utf8 他的结构为 CONSTANT_Utf8_info{ u1 tag; u2 length; u1 bytes[length];
表示长度为10 在接下来是数组的起始地址,长度为10 那么就是10个u1 我们翻一下ASCII码表,对照下十六进制与字符 48 H 65 e 6C l 6C l 6F o 57 W 6F o 72 r 6C l 64 d 也就是HelloWorld 这其实就是我们的类名 |
classFile文件格式
ClassFile { u4 magic;//唯一作用是确定这个文件是否为一个能被虚拟机所接受的class文件。魔数值固定为0xCAFEBABE,不会改变 u2 minor_version;//唯一作用是确定这个文件是否为一个能被虚拟机所接受的class文件。魔数值固定为0xCAFEBABE,不会改变 u2 major_version;//主版本号 u2 constant_pool_count;//常量池计数 值等于常量池表中的成员个数加1 cp_info constant_pool[constant_pool_count-1];//常量池 1~ constant_pool_count-1 为索引 u2 access_flags;//访问标志以及类型信息 u2 this_class;//当前类索引 指向常量池中一个CONSTANT_Class_info u2 super_class;//父类索引 0 或者指向常量池中一个CONSTANT_Class_info u2 interfaces_count;//直接超接口数量 u2 interfaces[interfaces_count];//接口表 u2 fields_count;//字段个数 static类变量或者非sttic的实例变量 不包括继承的 field_info fields[fields_count];//字段表 u2 methods_count;//方法个数 所有方法 但不包括继承而来的 method_info methods[methods_count];//方法表 u2 attributes_count;//属性个数 attribute_info attributes[attributes_count];/属性表 }
各种名称的内部表示形式
名称描述
描述符
形式是
FieldType
|
B | byte | [基本类型] 有符号的字节数组 |
C | char | [基本类型] 基本多语种平面中的Unicode代码点 UTF-16 |
D | double | [基本类型] 双精度浮点数 |
F | float | [基本类型] 单精度浮点数 |
I | int | [基本类型] 整型数 |
J | long | [基本类型] 长整数 |
S | short | [基本类型] 有符号短整数 |
Z | boolean | [基本类型] 布尔值true/false |
L ClassName; | L ClassName; | [对象类型] ClassName类的实例 |
[ | reference | [数组类型] 一维数组 |
形式是
( {ParameterDescriptor} ) ReturnDescriptor
注意: {} 不是一部分,是想表达和数组似的,也可能是多个
|
class文件详解之类本身信息
名称 | 值 | |
ACC_PUBLIC | 0x0001 | 声明为public 包外访问 |
ACC_FINAL | 0x0010 | final 不允许子类 |
ACC_SUPER | 0x0020 | 调用invokespecial 需要处理父类 |
ACC_INTERFACE | 0x0200 | 这是一个接口 |
ACC_ABSTRACT | 0x0400 | abstract 抽象的不能被实例化 |
ACC_SYNTHETIC | 0x1000 | class文件并非由java源代码生成 |
ACC_ANNOTATION | 0x2000 | 注解 |
ACC_ENUM | 0x4000 | 枚举 |
class文件详解之常量池
主要分为两类 字面量 符号引用
字面量类似java语言层面的含义 文本字符串 声明为final 的常量值
符号引用包括:
类和接口的全限定名
字段的名称和描述符
方法的名称和描述符
常量池包含了class文件结构及其子结构中引用的所有的,字符串常量,类或者接口名,字段名,以及其他常量
|
常量池中的表结构的类型可以分为三种类型
基本数据类型,比如 int long的描述形式,
虽然class文件是二进制字节流,最小为u1 但是这些基本数据类型在逻辑意义上来说,才是最小的描述单位
|
用于表述, 用于描述各个部分包含的逻辑内容的表 "结构体" 复合形式的数据类型结构
|
中间的映射结构表 相当于数据库中的中间关系表
|
cp_info{
u1 tag;
u1 info[];
}
CONSTANT_Class | 7 |
CONSTANT_Fieldref | 9 |
CONSTANT_Methodref | 10 |
CONSTANT_InterfaceMethodref | 11 |
CONSTANT_String | 8 |
CONSTANT_Integer | 3 |
CONSTANT_Float | 4 |
CONSTANT_Long | 5 |
CONSTANT_Double | 6 |
CONSTANT_NameAndType | 12 |
CONSTANT_Utf8 | 1 |
CONSTANT_MethodHandle | 15 |
CONSTANT_MethodType | 16 |
CONSTANT_InvokeDynamic | 18 |
常量池中的基础数据类型部分
字符串常量 |
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
|
tag是CONSTANT_Utf8 1 字符串采用改进过的UTF-8编码表示 接下来是编码后的字符串占用字节数以及字符串 class文件中的方法字段名称都是此类型 |
int整型 4字节 |
CONSTANT_Integer_info {
u1 tag;
u4 bytes;
}
|
tag为CONSTANT_Integer 3 大端排序的int值 |
单精度浮点型 float 4字节 |
CONSTANT_Float_info {
u1 tag;
u4 bytes;
}
|
tag为CONSTANT_Float 4 大端排序 IEEE754单精度格式 的floa值 |
long 长整型 8字节 |
CONSTANT_Long_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
|
tag为CONSTANT_Long 5 大端排序的long值 |
双精度浮点型 double 8字节 |
CONSTANT_Double_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
|
tag为CONSTANT_Double 6 大端排序的 double值 |
常量池中的中间关系映射类型部分
CONSTANT_NameAndType_info {
u1 tag;
u2 name_index;
u2 descriptor_index;
}
|
tag为 CONSTANT_NameAndType (12) NameAndType 就是名称和类型的意思 对于方法 / 字段 来说, 他们都有变量名称或者方法名称 他们也都有变量类型和方法签名(方法的类型) NameAndType 是作为一个中间表形式的数据结构 字段/方法中都有一个索引指向他,他又指向了实际的名称和类型 不管是方法名称还是字段名称 不管是方法签名还是字段类型都是字符常量的形式 name_index 和 descriptor_index 指向的都是CONSTANT_Utf8_info |
常量池中的复合数据类型部分
String类型的常量对象
|
CONSTANT_String_info {
u1 tag;
u2 string_index;
}
|
tag为CONSTANT_String 8
他表示的是String类型的数据,我们知道String是常量
字符串常量是用CONSTANT_Utf8_info进行表示的
所以 String_index指向的就是对应的CONSTANT_Utf8_info的"行号"
|
方法类型 |
CONSTANT_MethodType_info {
u1 tag;
u2 descriptor_index;
}
|
CONSTANT_MethodType 16 CONSTANT_NameAndType_info 是一个用于字段或者方法结构中的中间结构,包含了名称和类型 CONSTANT_MethodType_info 仅仅表示的就是方法签名 方法签名对应的是CONSTANT_Utf8_info 所以descriptor_index 指向 方法类型描述符的CONSTANT_Utf8_info |
类或接口 |
CONSTANT_Class_info {
u1 tag;
u2 name_index;
}
|
tag 为CONSTANT_Class 7 名称自然是字符串常量也就是CONSTANT_Utf8_info 所以 name_index指向常量池中的 CONSTANT_Utf8_info |
字段 |
CONSTANT_Fieldref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
|
CONSTANT_Fieldref 9 class_index 表示当前字段 对应或者说所属的 类或者接口 类和接口都可能 class_index指向CONSTANT_Class_info name_and_type_index 表示当前字段的名称和类型 name_and_type_index指向CONSTANT_NameAndType_info |
方法 |
CONSTANT_Methodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
|
CONSTANT_Methodref 10 class_index 表示当前方法 对应或者说所属的类,必须是类,不能是接口 class_index指向CONSTANT_Class_info name_and_type_index 表示当前方法的名称和方法签名
name_and_type_index指向CONSTANT_NameAndType_info
|
接口方法 |
CONSTANT_InterfaceMethodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
|
CONSTANT_InterfaceMethodref 11 class_index 表示当前方法 对应或者说所属的接口,必须是接口 不能是类 class_index指向CONSTANT_Class_info name_and_type_index 表示当前方法的名称和方法签名
name_and_type_index指向CONSTANT_NameAndType_info
|
方法调用 |
CONSTANT_MethodHandle_info {
u1 tag;
u1 reference_kind;
u2 reference_index;
}
|
CONSTANT_MethodHandle 15 方法调用,顾名思义也就是描述 方法的调用 对于一个方法调用来说,方法可能有不同的类型,不同的类型有不同的操作对象 reference_kind 正是描述方法的调用类型 reference_index 描述的是方法的操作目标 reference_kind 的值为1~9 他的类型决定了方法句柄的类型 句柄类型的值表示方法句柄中字节码行为 |
用于表示invokedynamic指令 |
CONSTANT_InvokeDynamic_info {
u1 tag;
u2 bootstrap_method_attr_index;
u2 name_and_type_index;
}
|
tag为CONSTANT_InvokeDynamic 18 CONSTANT_InvokeDynamic_info是为了字节码指令 invokedynamic 使用的 invokedynamic是为了更好的支持动态类型语言,Java7通过JSR292给JVM增加的一条新的字节码指令 bootstrap_method_attr_index 的值必须是对当前Class文件中引导方法表的bootstrap_methods[] 数组的有效索引 name_and_type_index 指向CONSTANT_NameAndType 表示方法名和方法描述符 |
class文件详解之字段
- 字段的作用域 public private protected
- 字段类型 类变量还是实例变量 是否有static修饰
- 是否为常量 final
- 并发可见性 volatile
- 是否可以被序列化 transient
- 字段的数据类型 基本类型 对象 数组
- 字段名称
字段 |
field_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
|
每个字段都由field_info结构定义 同一个class文件中不会有两个字段同时具有相同的字段名和描述符 access_flags 表示字段访问权限和基本属性 name_index指向字段的名字 CONSTANT_utf8_info descriptor_index 指向字段描述符CONSTANT_utf8_info 字段field 包含属性表,属性表结构的情况稍后介绍 |
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 |
ACC_SYNTHETIC | 0x1000 | 字段是否由编译器产生 |
ACC_ENUM | 0x4000 | 字段是否为enum |
class文件详解之方法
方法 |
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
|
所有方法,包括实例初始化方法以及类或者接口初始化方法 一个class文件中不会有两个方法具有相同的方法名和描述符 name_index 指向方法名字 CONSTANT_Utf8_info descriptor_index 表示方法描述符 指向 CONSTANT_Utf8_info 方法也有属性表 |
ACC_PUBLIC | 0x0001 | 方法是否为public 包外访问 |
ACC_PRIVATE | 0x0002 | 方法是否为private 当前类访问 |
ACC_PROTECTED | 0x0004 | 方法是否为protected 子类访问 |
ACC_STATIC | 0x0008 | 方法是否为static |
ACC_FINAL | 0x0010 | 方法是否为final |
ACC_SYNCHRONIZED | 0x0020 | 方法是否为synchronized |
ACC_BRIDGE | 0x0040 | 方法是否为 编译器为了字节码兼容自动生成的bridge方法 |
ACC_VARARGS | 0x0080 | 方法是否为变长参数 |
ACC_NATIVE | 0x0100 | 方法是否为native 本地方法 |
ACC_ABSTRACT | 0x0400 | 方法是否为abstract 无实现代码 |
ACC_STRICT | 0x0800 | 方法是否为strictfp 使用FP-strict浮点模式 |
ACC_SYNTHETIC | 0x1000 | 方法是否为编译器自动产生而不是由源代码编译而来 |
class文件详解之属性
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
所有的属性按照用途,可以划分为三类
1.对于JVM 正确解读class文件起关键作用的5个属性 • ConstantValue
• Code
• StackMapTable
• Exceptions
• BootstrapMethods
|
2.对JavaSE 平台类库正确解读class文件起关键作用的12个属性 • InnerClasses
• EnclosingMethod
• Synthetic
• Signature
• RuntimeVisibleAnnotations
• RuntimeInvisibleAnnotations
• RuntimeVisibleParameterAnnotations
• RuntimeInvisibleParameterAnnotations
• RuntimeVisibleTypeAnnotations
• RuntimeInvisibleTypeAnnotations
• AnnotationDefault
• MethodParameters
|
对JVM或者JavaSE平台类库能够正确解读class文件 虽然不起关键作用,但是却可以作为实用工具来使用的6个属性 • SourceFile
• SourceDebugExtension
• LineNumberTable
• LocalVariableTable
• LocalVariableTypeTable
• Deprecated
|
所有属性按照位置划分
属性 | 位置 | 备注 | 首次出现版本号 |
SourceFile
|
ClassFile | 表示class文件的源文件名称 类独有属性 |
45.3 |
InnerClasses
|
ClassFile | 内部类相关信息 类独有属性 |
45.3 |
EnclosingMethod
|
ClassFile | class为局部类或者匿名类才具有 类独有属性 |
49.0 |
SourceDebugExtension
|
ClassFile | 可选/保存扩展调试信息/最多一个 类独有属性 |
49.0 |
BootstrapMethods | ClassFile |
与 invokedynamic指令
常量池中CONSTANT_InvokeDynamic_info
相关
类独有属性
|
51.0 |
ConstantValue | field_info | fina修饰的字段的常量值 字段独有属性 |
45.3 |
Code | method_info | java程序方法体中的代码经过javac编译器处理后 最终变为字节码指令存储在Code属性内 Code属性出现在方法表的属性集合中 抽象类和接口不存在code属性 包含了方法的java虚拟机指令及相关辅助信息 方法独有属性 |
45.3 |
Exceptions | method_info | 方法可能抛出的已检查异常列表 方法独有属性 |
45.3 |
RuntimeVisibleParameterAnnotations,
RuntimeInvisibleParameterAnnotations
|
method_info | 形参上的运行时的注解信息类型 分为可见和不可见两种类型 方法独有属性 |
49.0 |
AnnotationDefault | method_info | method_info表示注解类型中的元素时 记录这个元素的默认值 方法独有属性 |
49.0 |
MethodParameters | method_info | 形参相关信息,比如参数名称 方法独有属性 |
52.0 |
Synthetic | classFile field_info method_info |
Synthetic 标志编译器生成 类 字段 方法都可能由编译器生成 所以三种都有此属性 |
45.3 |
Deprecated | classFile field_info method_info |
语义同@Deprecated 显然可以标注在类/接口/字段/方法上 所以三种都有此属性 |
45.3 |
Signature |
classFile
field_info
method_info
|
泛型信息 类接口 字段 方法 都有可能有类型参数 所以三种都有此属性 |
49.0 |
RuntimeVisibleAnnotations,
RuntimeInvisibleAnnotations
|
classFile
field_info
method_info
|
类 方法 字段上 运行时注解的可见性 分为可见不可见两种类型 三种都有此属性 |
49.0 |
LineNumberTable | Code | 调试用信息 用于调试器确定源文件中给定行号所表示的内容,对应于虚拟机中code[]数组中的哪一部分 也就是行号与字节码指令的对应关系 |
45.3 |
LocalVariableTable | Code | 调试用信息 调试器执行方法过程中可以用它来确定某个局部变量的值 |
45.3 |
LocalVariableTypeTable | Code |
调试用信息
调试器执行方法过程中可以用它来确定某个局部变量的值
|
49.0 |
StackMapTable | Code | 虚拟机类型检查验证使用信息 | 50.0 |
RuntimeVisibleTypeAnnotations,
RuntimeInvisibleTypeAnnotations
|
classFile
field_info
method_info
|
类/方法/字段声明所使用的类型上面的运行时注解可见性 分为可见/不可见两种 三种都有此属性 |
52.0 |
变换一种组织形式
classFile |
SourceFile
InnerClasses
EnclosingMethod
SourceDebugExtension
BootstrapMethods
Synthetic
Deprecated
Signature
RuntimeVisibleAnnotations,
RuntimeInvisibleAnnotations
RuntimeVisibleTypeAnnotations,
RuntimeInvisibleTypeAnnotations
|
field_info |
ConstantValue
Synthetic
Deprecated
Signature
RuntimeVisibleAnnotations,
RuntimeInvisibleAnnotations
RuntimeVisibleTypeAnnotations,
RuntimeInvisibleTypeAnnotations
|
method_info |
Code
Exceptions
RuntimeVisibleParameterAnnotations,
RuntimeInvisibleParameterAnnotations
AnnotationDefault
MethodParameters
Synthetic
Deprecated
Signature
RuntimeVisibleAnnotations,
RuntimeInvisibleAnnotations
RuntimeVisibleTypeAnnotations,
RuntimeInvisibleTypeAnnotations
|
Code |
LineNumberTable
LocalVariableTable
LocalVariableTypeTable
StackMapTable
|
ConstantValue 属性
ConstantValue_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 constantvalue_index;
}
|
Code属性
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack;
u2 max_locals;
u4 code_length;
u1 code[code_length];
u2 exception_table_length;
{ u2 start_pc;
u2 end_pc;
u2 handler_pc;
u2 catch_type;
} exception_table[exception_table_length];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
|
ps:
虚拟机栈是线程私有的,每创建一个线程,虚拟机就会为这个线程创建一个虚拟机栈
虚拟机栈表示Java方法执行的内存模型,每调用一个方法就会为每个方法生成一个栈帧(Stack Frame),用来存储局部变量表、操作数栈、动态链接、方法出口等信息。
每个方法被调用和完成的过程,都对应一个栈帧从虚拟机栈上入栈和出栈的过程。
虚拟机栈的生命周期和线程是相同的
|
StackMapTable属性
StackMapTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_entries;
stack_map_frame entries[number_of_entries];
}
|
union stack_map_frame {
same_frame;
same_locals_1_stack_item_frame;
same_locals_1_stack_item_frame_extended;
chop_frame;
same_frame_extended;
append_frame;
full_frame;
}
|
Exceptions属性
Exceptions_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_exceptions;
u2 exception_index_table[number_of_exceptions];
}
|
BootstrapMethods 属性
BootstrapMethods_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 num_bootstrap_methods;
{ u2 bootstrap_method_ref;
u2 num_bootstrap_arguments;
u2 bootstrap_arguments[num_bootstrap_arguments];
} bootstrap_methods[num_bootstrap_methods];
}
|
InnerClasses 属性
InnerClasses_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_classes;
{ u2 inner_class_info_index;
u2 outer_class_info_index;
u2 inner_name_index;
u2 inner_class_access_flags;
} classes[number_of_classes];
}
|
ACC_PUBLIC | 0x0001 | 内部类是否为public |
ACC_PRIVATE | 0x0002 | 内部类是否为private |
ACC_PROTECTED | 0x0004 | 内部类是否为protected |
ACC_STATIC | 0x0008 | 内部类是否为static |
ACC_FINAL | 0x0010 | 内部类是否为final |
ACC_INTERFACE | 0x0200 | 内部类是否为interface |
ACC_ABSTRACT | 0x0400 | 内部类是否为abstract |
ACC_SYNTHETIC | 0x1000 | 内部类是否为编译器自动生成 |
ACC_ANNOTATION | 0x2000 | 内部类是否为注解 |
ACC_ENUM | 0x4000 | 内部类是否为枚举 |
Synthetic 属性
Synthetic_attribute {
u2 attribute_name_index;
u4 attribute_length;
}
|
Signature 属性
Signature_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 signature_index;
}
|
EnclosingMethod 属性
EnclosingMethod_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 class_index;
u2 method_index;
}
|
RuntimeVisibleAnnotations 属性 RuntimeInvisibleAnnotations 属性
RuntimeVisibleAnnotations_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 num_annotations;
annotation annotations[num_annotations];
}
|
RuntimeInvisibleAnnotations_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 num_annotations;
annotation annotations[num_annotations];
}
|
annotation {
u2 type_index;
u2 num_element_value_pairs;
{ u2 element_name_index;
element_value value;
} element_value_pairs[num_element_value_pairs];
}
type_index 用来表示一个字段描述符,字段描述符表示一个注解类型
和当前annotation 结构所表示的注解一致
num_element_value_pairs 表示注解中的键值对 (注解中的参数都是键值对) 的个数
element_value_pairs 代表真正的键值对
它包括
element_name_index表示键
element_value 表示值
element_value {
u1 tag;
union {
u2 const_value_index;
{ u2 type_name_index;
u2 const_name_index;
} enum_const_value;
u2 class_info_index;
annotation annotation_value;
{ u2 num_values;
element_value values[num_values];
} array_value;
} value;
}
element_value 表示一个联合体
tag 使用u1 来表示键值对中的值是什么类型
也就是决定了键值对中 值的格式与value 中的哪一项相符合
联合体总共有五种
const_value_index
enum_const_value
class_info_index
annotation_value
array_value
|
B | byte | const_value_index | CONSTANT_Integer |
C | char | const_value_index | CONSTANT_Integer |
D | double | const_value_index | CONSTANT_Double |
F | float | const_value_index | CONSTANT_Float |
I | int | const_value_index | CONSTANT_Integer |
J | long | const_value_index | CONSTANT_Long |
S | short | const_value_index | CONSTANT_Integer |
Z | boolean | const_value_index | CONSTANT_Integer |
s | String | const_value_index | CONSTANT_Utf8 |
e | Enum类型 | enum_const_value | 不适用 |
c | Class | class_info_index | 不适用 |
@ | Annotation类型 | annotation_value | 不适用 |
[ | Array 类型 | array_value | 不适用 |
const_value_index 表示原始类型的常量值 或者String类型的字面量 |
enum_const_value 表示一个枚举常量
type_name_index 指向CONSTANT_Utf8_info 枚举常量类型的二进制名称的内部形式
const_name_index 指向CONSTANT_Utf8_info 枚举常量的简单名称
|
class_info_index 表示类字面量 CONSTANT_Utf8_info 用于表示返回描述符 返回描述符给出了与该element_value结构所表示的类字面量相对应的类型
如果类字面量是C. class,且C是类、接口或数组类型的名字,那么对应的类型就是C。常量池中的返回描述符会是ObjectType 或者ArrayType
如果类字面量是p. class,且p是原始类型的名称,那么对应的类型就是p 常量池中的返回描述符会是一个BaseType
如果类字面量是void. class,那么对应的类型就是void。常量池中的返回描述符会是V.
比如Object.class 对应于类型Object 所以常量池中就是Ljava/lang/Object; 而 int.class对应于类型int 常量池中就是I(大写的i )
|
annotation_value 表示键值对中里面的值本身又是一个注解 |
array_value 表示键值对的 值 是一个数组
num_values 给出了当前element_value结构所表示的数组的成员数量
values 每个成员对应了当前element_value 结构所表示的数组中的一个元素
|
RuntimeVisibleTypeAnnotations 属性 RuntimeInvisibleTypeAnnotations 属性
RuntimeVisibleTypeAnnotations_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 num_annotations;
type_annotation annotations[num_annotations];
}
|
RuntimeInvisibleTypeAnnotations_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 num_annotations;
type_annotation annotations[num_annotations];
}
|
type_annotation {
u1 target_type;
union {
type_parameter_target;
supertype_target;
type_parameter_bound_target;
empty_target;
method_formal_parameter_target;
throws_target;
localvar_target;
catch_target;
offset_target;
type_argument_target;
} target_info;
type_path target_path;
u2 type_index;
u2 num_element_value_pairs;
{ u2 element_name_index;
element_value value;
} element_value_pairs[num_element_value_pairs];
}
|
RuntimeVisibleParameterAnnotations 属性 RuntimeInvisibleParameterAnnotations 属性
RuntimeVisibleParameterAnnotations_attribute {
u2 attribute_name_index;
u4 attribute_length;
u1 num_parameters;
{ u2 num_annotations;
annotation annotations[num_annotations];
} parameter_annotations[num_parameters];
}
|
RuntimeInvisibleParameterAnnotations_attribute {
u2 attribute_name_index;
u4 attribute_length;
u1 num_parameters;
{ u2 num_annotations;
annotation annotations[num_annotations];
} parameter_annotations[num_parameters];
}
|
AnnotationDefault 属性
AnnotationDefault_attribute {
u2 attribute_name_index;
u4 attribute_length;
element_value default_value;
}
|
MethodParameters 属性
name_index 要么是0要么指向CONSTANT_Utf8_info 表示一个有效的非限定名 用来指代某个形式参数
access_flags ACC_FINAL 0x0010 形参为final
ACC_SYNTHETIC 0x1000 形参没有显式或者隐式的在源代码中声明,由编译器生成
ACC_MANDATED 0x8000 形参是隐式声明,也就是编程语言规范对所有的编译器的要求必须生成
MethodParameters_attribute {
u2 attribute_name_index;
u4 attribute_length;
u1 parameters_count;
{ u2 name_index;
u2 access_flags;
} parameters[parameters_count];
}
|
sourceFile 属性
SourceFile_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 sourcefile_index;
}
|
SourceDebugExtension 属性
SourceDebugExtension_attribute {
u2 attribute_name_index;
u4 attribute_length;
u1 debug_extension[attribute_length];
}
|
LineNumberTable 属性
LineNumberTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 line_number_table_length;
{ u2 start_pc;
u2 line_number;
} line_number_table[line_number_table_length];
}
|
LocalVariableTable 属性
LocalVariableTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 local_variable_table_length;
{ u2 start_pc;
u2 length;
u2 name_index;
u2 descriptor_index;
u2 index;
} local_variable_table[local_variable_table_length];
}
|
LocalVariableTypeTable 属性
LocalVariableTypeTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 local_variable_type_table_length;
{ u2 start_pc;
u2 length;
u2 name_index;
u2 signature_index;
u2 index;
} local_variable_type_table[local_variable_type_table_length];
}
|
Deprecated 属性
Deprecated_attribute {
u2 attribute_name_index;
u4 attribute_length;
}
|
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- Spring Boot 实现配置文件加解密原理 2020-06-08
- Java跨平台原理(字节码文件、虚拟机) 以及Java安全性 2020-06-07
- 【Java-jxl插件】【Excel文件读写报错】jxl.read.biff.BiffE 2020-06-07
- IDEA下Maven的pom文件导入依赖出现Auto build completed wit 2020-06-07
- Java中jar包获取资源文件的方式 2020-06-05
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash