JVM实探-class文件格式(1)

每个class文件对应一个如下所示的ClassFile结构体

ClassFile {
    u4 magic; #魔数
    u2 minor_version; #class文件副版本号,JDK版本
    u2 major_version; #class文件主版本号,JDK版本
    u2 constant_pool_count; #常量池数量
    cp_info constant_pool[constant_pool_count-1]; #常量池
    u2 access_flags; #访问标志
    u2 this_class; #类索引,对应constant_pool表中的一个有效索引值
    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]; #属性表
}

一、魔数

魔数的唯一作用是标记这个文件是否是一个可被虚拟机识别的class文件,魔数固定值为0xCAFEBABE,不会改变。(传说好像java一直为咖啡代言哈... ...)。

二、主副版本号

major_version、minor_version,共同构建了class文件格式版本号,eg:major_version=M,minor_version=m,那么该class文件格式版本号为M.m。

一个java虚拟机实例只能支持特定范围内的主版本号(Mi至Mj)和0至特定范围的副版本号,假设一个class文件的格式版本号为V,仅当Mi.0<v<Mj.m成立时,这个class文件才可以被此java虚拟机支持。高版本java虚拟机可以支持低版本class文件,反之不行。以下JDK版本对应到1.8,更高的以此类推即可。

JDK版本号Class版本号16进制
1.145.000 00 00 2D
1.246.000 00 00 2E
1.347.000 00 00 2F
1.448.000 00 00 30
1.549.000 00 00 31
1.650.000 00 00 32
1.751.000 00 00 33
1.852.000 00 00 34

三、常量池计数器

constant_pool_count等于constant_pool表中的成员数加1(想想为什么+1,段位最后一句为解释)。constant_pool表的索引值只有在大于0且小于constant_pool_count时才会被认为是有效的,对于long合double类型有列外的情况。值为0的constant_pool索引是无效的,当其他数据结构用到0的索引来表示“不引用任何一个常量池项”的意思。

四、常量池

constant_pool是一种表结构,它包含Class文件结构及其子结构中引用的所有字符串常量、类或接口名、字段名和其他常量。常量池中的每一项都具备相同的格式特征——第一个字节作为类型标记用于识别该项是哪种类型的常量,称为“tag byte”。常量池的索引范围是1至constant_pool_count-1.格式如下

cp_info {
    u1 tag;
    u1 info[];
}

tag项说明如下:

常量类型
CONSTANT_Class7
CONSTANT_Fieldref9
CONSTANT_Methodref10
CONSTANT_InterfaceMethodref11
CONSTANT_String8
CONSTANT_Integer3
CONSTANT_Float4
CONSTANT_Long5
CONSTANT_Double6
CONSTANT_NameAndType12
CONSTANT_Utf81
CONSTANT_MethodHandle15
CONSTANT_MethodType16
CONSTANT_InvokeDynamic18

 

以上tag中项的格式说明详见:constant_pool格式详解

五、访问标识

access_flags是一种掩码标志,用于表示某个类或者接口的访问权限及基础属性。eg:0x0021=0x0020 | 0x0001->ACC_PUBLIC | ACC_SUPER

标志名标志值标志含义针对的对像
ACC_PUBLIC0x0001public类型所有类型
ACC_FINAL0x0010final类型
ACC_PROTECTED0x0004protected; 可以在子类中访问 
ACC_SUPER0x0020使用新的invokespecial语义类和接口
ACC_INTERFACE0x0200接口类型接口
ACC_ABSTRACT0x0400抽象类型类和接口
ACC_SYNTHETIC0x1000该类不由用户代码生成所有类型
ACC_ANNOTATION0x2000注解类型注解
ACC_ENUM0x4000枚举类型枚举
ACC_STATIC0x0008申明为static所有
ACC_VOLATILE0x0040volatile; 不能被缓存. 
ACC_TRANSIENT0x0080transient; 持久化对象管理器不会读和写. 

ACC_SYNTHETIC:由编译器自己产生的而不是由程序员编写的源代码生成的,以下为该类型的解释。

package com.weyne.demo.jvm;

public class SyntheticDemo {
    public static void main(String[] args) {
        InnerClassDemo innerClassDemo = new InnerClassDemo();
        System.out.println(innerClassDemo.hashCode());
    }

    private static class InnerClassDemo{
        private String a = "私有类部类";
    }
}

该类编译后在本地生成有SyntheticDemo$1.class、SyntheticDemo$InnerClassDemo.class、SyntheticDemo.class,其中SyntheticDemo$1.class就为ACC_SYNTHETIC类型,javap -v XXX.class查看class结构

六、类索引

this_class,值为constant_pool中的一个有效索引值,且constant_pool中的该项为CONSTANT_Class_info类型常量,表示这个class文件所定义的类或接口。

七、父类索引

super_class,对于类而言,该值必须为0或者对应constant_pool表中的一个有效索引值,如果不为0,那constant_pool表在这个索引处的项必须为CONSTANT_Class_info类型常量,表示这个Class文件所定义的类的直接父类。当前类的直接父类以及他所有的间接父类的access_flag中都不能带有ACC_FINAL。如果值为0,则该类可能为java.lang.Object,只有它是唯一没有父类的类。

八、接口计数器

interface_count,表示当前类或接口的直接父接口数量.

九、接口表

interfaces[],长度为interface_count,值对应constant_pool中的有效索引值,成员必须为CONSTANT_Class_info。成员所表示的接口顺序和对应的源代码中给定的接口顺序(从左至右)一样。

10、字段计数器
field_count,表示当前Class文件fields[]数组的成员个数,fields[]数组中的每一项都是field_info接口,用于表示该类或接口声明的类字段或者实例字段。类字段即被声明为static的字段,也称类变量或类属性,实例字段是指未被声明为static的字段。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值