Class文件格式(1)-常量池

1.Class文件格式

    根据Java虚拟机描述,Class文件中数据的排列并不需要严格的字节对齐,因此字节与字节之间没有"空隙",各个字节所处的位置以及所表达的含义都是严格限定的,对于多字节数据,严格按照大端模式存储。
     能够被JVM识别并执行的Class文件或者网络字节流应该具有如下格式:

    1.1、magic

        magic为JVM所能够识别的魔术,占用4个字节空间,此值固定的十六进制格式数据位:0xCAFEBABE,谐音:咖啡Baby。

    1.2、主次版本号

        主次版本号用于确定该类文件能够在哪些版本的虚拟器上运行。

    1.3、常量池

        常量池存放字符串常量、类或者接口的名称等常量信息。

    1.4、访问标志

        决定类文件访问权限的掩码值。

    1.5、this\supper  class

        表示类以及类父类信息。

    1.6、interfaces

        当前类或者接口的直接父接口。

    1.7、fields

        当前类或者接口测字段描述信息,不包括父类或者父接口中的字段信息。

    1.8、methods

        当前类或者接口的方法描述,不考考父类或者父接口中的方法描述。

    1.9、attributes

        描述Class文件的属性信息。

2.常量池

    2.1、常量池结构

         常量池中存放如下14中类型的常量信息,常量池的单项结构可以通过cp_info表示,tag为标记,取值范围如下所示,不同的tag值对应不同的常量项结构。

    2.2、Utf8

        Utf8结构用于表示字符串常量的值。
        tag值为1,表示CONSTANT_Utf8。
        length表示bytes数组的长度。
        bytes[]表示存储字符串值得byte数组,每个byte的值不能够是0,也不能够是0xf0~0xff之间的数。
       '\u0001'到 '\u007f'之间的字符使用单字节表示,从 '\u0080'到 '\u07ff'之间的字符用双字节表示,从 '\u0800'到 '\uffff'之间的字符,用三字节表示,高于'\uffff'的字符,用6字节表示,表示方式可以参考Java虚拟机规范一书

        在Hotspot中,与Utf8编码相关的接口位于:\hotspot\src\share\vm\utilities\utf8.cpp,具体如下:
bool UTF8::is_supplementary_character(const unsigned char* str) {
  return ((str[0] & 0xFF) == 0xED) && ((str[1] & 0xF0) == 0xA0)
      && ((str[2] & 0xC0) == 0x80) && ((str[3] & 0xFF) == 0xED)
      && ((str[4] & 0xF0) == 0xB0) && ((str[5] & 0xC0) == 0x80);
}
jint UTF8::get_supplementary_character(const unsigned char* str) {
  return 0x10000 + ((str[1] & 0x0f) << 16) + ((str[2] & 0x3f) << 10)
                 + ((str[4] & 0x0f) << 6)  + (str[5] & 0x3f);
}
int UNICODE::utf8_size(jchar c) {
  if ((0x0001 <= c) && (c <= 0x007F)) return 1;
  if (c <= 0x07FF) return 2;
  return 3;
}
// Writes a jchar a utf8 and returns the end
static u_char* utf8_write(u_char* base, jchar ch) {
  if ((ch != 0) && (ch <=0x7f)) {
    base[0] = (u_char) ch;
    return base + 1;
  }

  if (ch <= 0x7FF) {
    /* 11 bits or less. */
    unsigned char high_five = ch >> 6;
    unsigned char low_six = ch & 0x3F;
    base[0] = high_five | 0xC0; /* 110xxxxx */
    base[1] = low_six | 0x80;   /* 10xxxxxx */
    return base + 2;
  }
  /* possibly full 16 bits. */
  char high_four = ch >> 12;
  char mid_six = (ch >> 6) & 0x3F;
  char low_six = ch & 0x3f;
  base[0] = high_four | 0xE0; /* 1110xxxx */
  base[1] = mid_six | 0x80;   /* 10xxxxxx */
  base[2] = low_six | 0x80;   /* 10xxxxxx */
  return base + 3;
}

    2.3、Integer

        表示整数的常量结构项。
         tag为3,表示CONSTANT_Integer。
         bytes占用4个字节,表示整数的具体指,存储方式为大端存储。

    2.4、Float

        按照IEEE 754单精度浮点格式表示的浮点数常量结构项。
        tag为4,表示CONSTANT_Float。
        bytes为存储浮点数的字节数组,以大端模式存储。

    2.5、Long

        长整形的常量结构项。
        tag为5,表示CONSTANT_Long。
        high_bytes和low_bytes表示组成64bit的Long型整数的高32位和低32位值,high_bytes和low_bytes分别以大端模式存储,通过((long) high_bytes << 32) + low_bytes方式构建64bit的整数。

    2.6、Double

        双精度浮点数常量结构项。
         双精度浮点数占用64bit,分别由两个4字节数组构成,换算方式见参加Java虚拟机规范。

    2.7、Class

        用于表示类或者借口的常量项。
        tag为7,表示CONSTANT_Class。
        name_index为一个2字节16位无符号整数,指向常量池中一个合法的索引,在该索引处存放CONSTANT_Utf8_info的常量项,代表Class的类名称或者接口名称。

    2.8、String

        用于表示字符串的常量项结构。
        tag为8,表示CONSTANT_String。
        string_index为两个字节16位的无符号整数,指向常量池中的有效索引,该索引处存放CONSTANT_Utf8_info类型的常量项,表示一组Unicode编码的序列,该序列最后用于字符串的初始化操作。

    2.9、Field

        用于表示字段的常量项结构。
        tag为9,表示CONSTANT_Fieldref。
        class_index为u2型整数,指向常量池中的有效索引,该索引处存放CONSTANT_Class_info常量项,描述此字段所属的类或者接口(类或者接口皆可)
        name_and_type_index为u2型整数,指向常量池的有效索引,该索引处存放CONSTANT_NameAndType_info,表示当前字段的描述符。

    2.10、Method

        用于表示方法的常量项结构。
        tag为10,表示CONSTANT_Methodref。
        class_index为u2型整数,指向常量池中的有效索引,该索引处存放CONSTANT_Class_info常量项,描述此方法所属的类(不能够是接口)。
        name_and_type_index为u2型整数,指向常量池的有效索引,该索引处存放CONSTANT_NameAndType_info,表示当前方法的描述符。如果方法以“<”('\u003c')开头,则说明这个方法名是特殊的<init>,即这个方法是实例初始化方法,它的返回类型必须为空。

    2.11、InterfaceMethod

        表示接口方法的常量项结构。
        tag为11,表示CONSTANT_InterfaceMethodref。
        class_index为u2型整数,指向常量池中的有效索引,该索引处存放CONSTANT_Class_info常量项,描述此方法所属的接口(不能是类)
        name_and_type_index为u2型整数,指向常量池的有效索引,该索引处存放CONSTANT_NameAndType_info,表示当前方法的描述符。

    2.12、NameAndType

        描述字段或者方法的常量项结构。
        tag为12,表示CONSTANT_NameAndType。
        name_index为u2类型的指向常量池的有效索引,该索引处存放CONSTANT_Utf8_info常量项,表示特殊方法<init>,或者表示字段、方法的非全限定名。
         descriptor_index和name_index一样,也是常量池中的一个Utf8常量项,表示字段或者方法的描述符。

    2.13、MethodHandle

        描述方法句柄的常量项结构。
        tag为15,表示CONSTANT_MethodHandle。
        reference_kind为单字节无符号整数,值为1~9之间的数字,标记方法的字节码行为。
        reference_index为u2类型整数,常量池的有效索引,根据reference_kind值的不同,该索引处存放的常量项可以使CONSTANT_Fieldref_info、CONSTANT_Methodref_info、CONSTANT_InterfaceMethodref_info。

        reference_kind的类型以及对应reference_index处的常量项类型如下:

        reference_kind值在1~4之间时,reference_index处所存放的常量项类型为CONSTANT_Fieldref_info,表示由一个类或者接口的字段创建的方法句柄。
        reference_kind值在5~8之间时,reference_index处所存放的常量项为CONSTANT_Mehtodref_info,表示由一个类的方法或者类的构造函数创建的方法句柄。
        reference_kind为9的时候,reference_index处所存放的常量项为CONSTANT_InterfaceMethodref_info,表示由一个接口的方法创建的方法句柄。
        refernece_kind的值为5、6、7、9时,reference_index处所存放的常量项所表示的方法不能够是实例初始化(<init>)方法或类初始化方法(<clinit>)。
        referenct_kind的值为8的时候,reference_index处所存放的常量项CONSTANT_Mehtodref_indo所描述的方法必须是实例初始化(<init>)方法。

    2.14、MethodType

         描述方法类型的常量项结构。
         tag为16,表示CONSTANT_MehtodType。
         descriptor_index为u2类型的指向常量池有效索引的整数,该索引处存放的是CONSTANT_Utf8_info常量项,表示该方法的描述符。

    2.15、InvokeDynamic

        表示invokedynamic指令所使用到的引导方法(Bootstrap Method)的相关信息,包括引导方法所使用到的动态调用名称(Dynamic Invocation Name)、参数、返回值类型、以及可以选的被称为静态参数(Static Arguments)的常量序列。
        tag为18,表示CONSTANT_InvokeDynamic。
        bootstrap_method_attr_index为u2类型的整数,为当前class文件的引导方法数组bootstrap_methods[]的一个有效下标。
         name_and_type_index为u2类型的常量池索引,该索引处存放CONSTANT_NameAndType_info常量项,表示方法的名称和方法的描述符。

3.definition

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

CONSTANT_Integer_info {
    u1 tag;
    u4 bytes;
}

CONSTANT_Float_info {
    u1 tag;
    u4 bytes;
}

CONSTANT_Long_info {
    u1 tag;
    u4 high_bytes;
    u4 low_bytes;
}

CONSTANT_Double_info {
    u1 tag;
    u4 high_bytes;
    u4 low_bytes;
}

CONSTANT_Class_info {
    u1 tag;
    u2 name_index;
}

CONSTANT_String_info {
    u1 tag;
    u2 string_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;
}

CONSTANT_NameAndType_info {
    u1 tag;
    u2 name_index;
    u2 descriptor_index;
}

CONSTANT_MethodHandle_info {
    u1 tag;
    u1 reference_kind;
    u2 reference_index;
}

CONSTANT_MethodType_info {
    u1 tag;
    u2 descriptor_index;
}

CONSTANT_InvokeDynamic_info {
    u1 tag;
    u2 bootstrap_method_attr_index;
    u2 name_and_type_index;
}
         
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值