一、class文件结构

class文件结构

结构

java虚拟机用u1、u2、u4表示1、2、4个字节的无符号整数。

classFile {
    u4                magic;  \\魔数
    u2                minor_version;  \\副版本号
    u2                major_version;  \\主版本号
    u2                constant_pool_count;  \\常量池大小
    cp                constant_pool[constant_pool_count - 1]  \\常量池,不定长
    u2                access_flags;  \\访问标记
    u2                this_class;  \\当前类索引
    u2                super_class;  \\直接父类索引
    u2                interfaes_count;  \\直接接口数
    u2                interfaces[interfaes_count];  \\直接接口索引
    u2                field_count;  \\成员变量数
    field_info        fields[filed_count];  \\成员变量
}
常量池

数据结构

cp_info {
    u1 tag;  \\类型
    u1 info[];  \\数据
}
  • CONSTANT_Integer_Info和CONSTANT_Float_Info
    两种结构相似,用4个字节来表示具体的数值常量。boolean、byte、short、char类型在常量池都当做int作处理。
CONSTANT_Integer_Info {
    u1 tag;
    u4 bytes;
}
CONSTANT_Float_Info {
    u1 tag;
    u4 bytes;
}
  • CONSTANT_Long_Info和CONSTANT_Double_Info
    二者都用8个字节表示具体数值,占用常量池的2个位置。
CONSTANT_Long_Info {
    u1 tag;
    u4 high_bytes;
    u4 low_bytes;
}
CONSTANT_Double_Info {
    u1 tag;
    u4 high_bytes;
    u4 low_bytes;
}
  • CONSTANT_Utf8_Info
    存储字符串的内容
CONSTANT_Long_Info {
    u1 tag;
    u2 length;  \\第三部分byte数组的长度
    u1 bytes[length];  \\内容数组,每个byte都是MUTF-8编码
}
  • CONSTANT_String_Info
    用来表示java.lang.String类型的常量对象,仅仅包含一个指向常量池中CONSTANT_Utf8_Info常量类型的索引。
CONSTANT_String_Info {
    u1 tag;
    u2 string_index;  \\表示指向CONSTANT_Utf8_Info的索引
}
  • CONSTANT_Class_Info
    与CONSTANT_String_Info类型,name_index表示指向CONSTANT_Utf8_Info的索引,这个字符串存储的是类或接口的全限定名
CONSTANT_Class_Info {
    u1 tag;
    u2 name_index;
}
  • CONSTANT_NameAndType_Info
    用来表示字段或者方法,name_index和descriptor_index都指向CONSTANT_Utf8_Info的索引。
CONSTANT_NameAndType_Info {
    u1 tag;
    u2 name_index;  \\字段或方法名的指向索引
    u2 descriptor_index;  \\字段或方法的描述符(签名)的指向索引
}
  • CONSTANT_Fieldref_Info、CONSTANT_Methodref_Info和CONSTANT_InterfaceMethodref_Info
    这三种常量类型比较类似,class_index表示指向类信息的索引,name_and_type_index表示方法或字段指向的类型的索引。
CONSTANT_Fieldref_Info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}
CONSTANT_Methodref_Info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}
CONSTANT_InterfaceMethodref_Info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}
Access flags(访问标记)

表示一个类的访问标志。

访问标记名十六进制值描述
ACC_PUBLIC1标识是否是public
ACC_FINAL10标识是否是final
ACC_SUPER20不再使用
ACC_INTERFACE200标识接口
ACC_ABSTRACT400标识是否是abstract
ACC_SYNTHETIC1000编译器自动生成,不是用户源代码编译生成
ACC_ANNOTATION2000标识是否是注解类
ACC_ENUM4000标识是否是枚举类
this_class、super_class、interfaces

用于确定类的继承关系,this_class表示类索引,super_class表示直接父类索引,interfaces表示当前类或接口的直接父接口
如this_class存储的是指向CONSTANTS_Class_Info的索引。

字段表

类中定义的字段都会被存储到这个集合中,包括静态和非静态的字段。

{
    u2          field_count;  \\字段数量
    filed_info  fileds[filed_count];  \\字段集合
}

字段表也是个变长的结构。field_info结构如下:

filed_info {
    u2              access_flag;
    u2              name_index;  \\指向CONSTANTS_Utf8_Info的索引
    u2              descriptor_index;  \\指向CONSTANTS_Utf8_Info的索引
    u2              attributes_count;
    attribute_info  attributes[attribute_count];
}
  • access_flag
    访问标记名|十六进制值|描述
    —|:—|:—:
    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_ENUM|0x4000|声明为枚举类型

如果类中定义了字段public static final int SIZE = 10,编译后在类文件中存储的访问标记值为0x0019,访问标志位ACC_PUBLIC|ACC_STATIC|ACC_FINAL

  • 字段描述符
    访问标记名|十六进制值
    —|:—:
    B | byte类型
    C | char类型
    D | double类型
    F | float类型
    I | int类型
    J | long类型
    S | short类型
    Z | boolean类型
    L ClassName;| 引用类型, “L” + 类的全限定名 + “;”
    [ | 一维数组
    [[ | 二维数组

  • 字段属性
    以ConstantValue为例
    ConstantValue属性出现在字段field_info中,用来表示静态变量的初始值,结构如下:

ConstantValue_attribute {
    u2  attribute_name_index;  \\指向常量池中值为“ConstantValue”的字符串常量项
    u4  attribute_length;  \\固定值为2
    u2  constantvalue_index;  \\根据变量类型不同指向不同的常量项
}

constantvalue_index根据变量类型不同指向不同的常量项,如变量是long类型,则constantvalue_index执行CONSTANT_Long_Info类型的常量项。

方法表

类中定义的方法会被存储在方法表里,结构如下:

{
    u2            methods_count;  \\方法的数量
    method_info   methods[methods_count];  \\方法的集合
}

方法method_info的结构如下:

method_info {
    u2              access_flags;  \\访问标志
    u2              name_index;  \\方法名索引
    u2              descriptor_index;  \\描述(签名)索引
    u2              attributes_count;  \\方法属性个数
    attribute_info  attributes[attributes_count];  \\方法属性
}
  • 方法属性
    Code属性
Code_attribute {
    u2  attribute_name_index;  \\属性名,对应“Code”的字符串常量索引
    u4  attribute_length;  \\属性长度
    u2  max_stack;  \\操作数栈的最大深度
    u2  max_locals;  \\局部变量表的大小
    u4  code_length;  \\方法的字节码长度
    u1  code[code_lenght];  \\字节码
    u2  exception_table_length;  \\异常数量
    {
        u2  start_pc;  \\异常处理器覆盖的code数组开始位置
        u2  end_pc;  \\异常处理器覆盖的code数组结束位置
        u2  handler_pc;  \\异常处理handler在code字节数组的起始位
        u2  catch_type;  \\catch的异常类型
    }  exception_table[exception_table_length];  \\异常数组
    u2  attributes_count;
    attribute_info  attributes[attributes_count];
}
  1. max_stack
    表示操作数栈的最大深度,方法执行的任意期间操作数栈的深度都不会超过这个值。计算规则是:有入栈的指令stack增加,有出栈的指令stack减少,stack的最大值就是max_stack。一般增加和减少都是1,但LONG和DOUBLE相关指令入栈会增加2,void指令则为0。
  2. max_locals
    表示局部变量表的大小,它的值并不等于方法中所有局部变量的数量之和。当一个局部作用域结束,它内部的局部变量占用的位置就可以被接下来的局部变量复用。
  3. exception_table
    表示try-catch相关。start_pc、end_pc、handler_pc都是指向code字节数组的索引值,start_pc和end_pc表示异常处理器覆盖的字节码开始和结束的位置,是左闭右开区间[start_pc, end_pc]。handler_pc表示异常处理handler在code字节数组的起始位置,表示异常捕获后该跳转至何处处理。
  4. attributes
    用于标识Code属性相关附属属性,java规定只包含四种可选属性:LineNumberTable、LocalVariableTable、LocalVariableTypeTable、StackMapTable。
    1. LineNumberTable用来存放源代码行号和字节码偏移量之间的对应关系属于调试信息,不是类文件运行的必需属性,默认情况下都会生成。如果没有该属性,调试时就无法在源码中设置断点,也没办法在抛出异常的堆栈中显示行号。
javap命令
  • -p 显示private信息
  • -s 显示签名信息
  • -c 反编译,显示方法的字节码
  • -v 显示详细信息,包括版本号、类访问权限、常量池等相关信息。
  • -l 显示行号
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值