[一]class 文件浅析 .class文件格式详解 字段方法属性常量池字段 class文件属性表 数据类型 数据结构
前言概述
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[];
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-];
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 u1 还有不定个数的u1 因为常量池计数为39 第一个tag CONSTANT_Class_info{ u1 tag; u2 name_index;
所以tag 之后,接下来有一个u2 表示name_index 在接下来的一个u1 是下一个常量池数据项的tag CONSTANT_Utf8_info{ u1 tag; u2 length; u1 bytes[length];
所以接下来的两个为length |
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~ 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;
}
|
[一]class 文件浅析 .class文件格式详解 字段方法属性常量池字段 class文件属性表 数据类型 数据结构的更多相关文章
- JVM详解之:运行时常量池
目录 简介 class文件中的常量池 运行时常量池 静态常量详解 String常量 数字常量 符号引用详解 String Pool字符串常量池 总结 简介 JVM在运行的时候会对class文件进行加载 ...
- DOS文件转换成UNIX文件格式详解
转:DOS文件转换成UNIX文件格式详解 由windows平台迁移到unix系统下容易引发的问题:Linux执行脚本却提示No such file or directory dos格式文件传输到uni ...
- BMP文件格式详解
BMP文件格式详解(BMP file format) BMP文件格式,又称为Bitmap(位图)或是DIB(Device-Independent Device,设备无关位图),是Windows系统中广 ...
- PE文件格式详解,第一讲,DOS头文件格式
PE文件格式详解,第一讲,DOS头文件格式 今天讲解PE文件格式的DOS头文件格式 首先我们要理解,什么是文件格式,我们常说的EXE可执行程序,就是一个文件格式,那么我们要了解它里面到底存了什么内容 ...
- PE文件格式详解,第二讲,NT头文件格式,以及文件头格式
PE文件格式详解,第二讲,NT头文件格式,以及文件头格式 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) PS:本篇博客 ...
- PE文件格式详解,第三讲,可选头文件格式,以及节表
PE文件格式详解,第三讲,可选头文件格式,以及节表 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) 一丶可选头结构以及作 ...
- Carbondata源码系列(二)文件格式详解
在上一章当中,写了文件的生成过程.这一章主要讲解文件格式(V3版本)的具体细节. 1.字典文件格式详解 字典文件的作用是在存储的时候将字符串等类型转换为int类型,好处主要有两点: 1.减少存储占用空 ...
- OpenGL学习--05--纹理立方体--BMP文件格式详解(转载)
http://blog.csdn.net/o_sun_o/article/details/8351037 BMP文件格式详解 BMP文件格式详解(BMP file format) BMP文件格式,又称 ...
- Android逆向之旅---SO(ELF)文件格式详解(转)
第一.前言 从今天开始我们正式开始Android的逆向之旅,关于逆向的相关知识,想必大家都不陌生了,逆向领域是一个充满挑战和神秘的领域.作为一名Android开发者,每个人都想去探索这个领域,因为一旦 ...
随机推荐
- go 统计目录大小
文件大小获取 // 这里获取的是 FileInfo 对象 fi, _ := os.Stat(filepath) FileInfo 定义如下: type FileInfo interface { Nam ...
- MYSQL必知必会学习笔记
8.1.1 百分号( %)通配符最常使用的通配符是百分号( %).在搜索串中, %表示任何字符出现任意次数.例如,为了找出所有以词jet起头的产品,可使用以下SELECT语句:SELECT prod_ ...
- LINUX监控-spotlight
这里连接的user不能是root(spotlight需要一个具有root权限的用户,但是又不允许是root),所以需要给要连接的linux端创建一个有root权限的用户,在linux主机创建了root ...
- lvm快照备份数据库(Mysql5.7)
备份的目的 能够防止由于机械故障以及人为误操作带来的数据丢失,例如将数据库文件保存在了其它地方. 备份的分类 以操作过程中服务的可用性分: 冷备份:cold backup mysql服务关闭,mysq ...
- 关于vue的数据增删的一些细节
第一种情况:在vue中使用的数据必须先在data中定义数据,不然报错: 第二种情况:访问对象中不存在的值,是可以得到undefined,但是不会报错 第三种:vue只会监听data已经定义的值,后续添 ...
- [LeetCode] Push Dominoes 推多米诺骨牌
There are N dominoes in a line, and we place each domino vertically upright. In the beginning, we si ...
- Vue 中动态添加class(使用v-bind:class)
今天在Vue中动态修改类名,元素的样式就是不改变,类名也没有加上去,里面的问题具体我还是不太清楚,有可能是因为自己不认真,把 :class= 后面的内容的格式给整错了,下面将正确的做法记录一下,便于以 ...
- Android Studio 设置不同分辨率的图标Icon
右键你的项目 -->"NEW"-->"Image Asset" 'Asset Type' 勾选”Image“才可以选择”Path“,其他选项可以自己 ...
- flex弹性布局心得
概述 最近做项目用flex重构了一下网页中的布局,顺便学习了一下flex弹性布局,感觉超级强大,有一些心得,记录下来供以后开发时参考,相信对其他人也有用. 参考资料: Solved by Flexbo ...
- Node.js(day4)
一.一些小问题 1.文件操作路径和模块读取路径的问题 我们使用fs核心模块系统进行文件操作时一般这样书写路径 fs.readFile('./views/index.html');//读取views目录 ...