class文件内容解析

class文件基本数据结构:

使用javac编译后的文件是.class文件,程序运行时,class文件被classLoader加载到JVM成为class对象,随后便可以创建该类的对象。

class文件是二进制文件流,记录类相关信息,可以被JVM解析。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];
}

magic:魔数,4bytes,固定的cafebabe,简单校验,另外也可作为流传输时的解析头。

minor_version:次版本

major_version:主版本

  • Java 1.2 uses major version 46
  • Java 1.3 uses major version 47
  • Java 1.4 uses major version 48
  • Java 5 uses major version 49
  • Java 6 uses major version 50
  • Java 7 uses major version 51
  • Java 8 uses major version 52
  • Java 9 uses major version 53
  • Java 10 uses major version 54
  • Java 11 uses major version 55

constant_pool_count:常量池元素个数,指导解析多少常量元素,实际个数是constant_pool_count - 1,2bytes意味着组多65535个常量了。

constant_pool:常量池元素

cp_info {
    u1 tag;
    u1 info[];
}

记录的格式大体上是tv和tlv的模式,其中tag有以下几种:

CONSTANT_Class 7 (类或接口名称,是一个index,指向常量池中String类型常量)
CONSTANT_Fieldref 9 (字段名称,类型,归属类)
CONSTANT_Methodref 10 (记录方法调用常量名称,含归属类,方法名称,描述(含入参和返回值,例如 (Ljava/util/Date;Ljava/lang/Integer;)Ljava/lang/String),入参是date和integer,返回值string)
CONSTANT_InterfaceMethodref 11 (使用接口调用方法)
CONSTANT_String 8 (字符串常量)
CONSTANT_Integer 3 (整数常量)
CONSTANT_Float 4 (浮点数常量)
CONSTANT_Long 5 (长整型常量)
CONSTANT_Double 6 (double常量)
CONSTANT_NameAndType 12 (名称和描述常量,被method_ref,field_ref等引用,记录扩展信息)
CONSTANT_Utf8 1 (字符串值)
CONSTANT_MethodHandle 15 (函数句柄,类反射功能)
CONSTANT_MethodType 16 (配合MethodHandle使用,描述方法入参和返回值)
CONSTANT_InvokeDynamic 18 (描述invokedynamic的方法)

access_flags:2bytes,描述类的访问权限,不同位具有不同含义,具体见java.lang.reflect.Modifier.isPublic(mod)相关的判断方法。

this_class:2bytes,寻址常量池中多有条目,记录当前类名称在cp中的索引。

super_class:2bytes,记录父类名称在cp索引,父类只能有一个。

interfaces_count:继承接口个数,2bytes。

interfaces:继承接口名称在cp里的引用。

fields_count:成员变量个数,2bytes。

fields:成员变量详情:

field_info {
    u2             access_flags;
    u2             name_index;
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

access_flags:同class上的access_flags,可选种类不同

name_index:名称在cp里的索引

descriptor_index:类型,泛型会被最小化到明确类

attributes_count:成员变量属性个数

attribute_info:属性具体内容,能用在field上的attribute有:

  • Synthetic:成员变量未出现在源码里,是被合成的。
  • Deprecated
  • Signature:泛型类型存在这里
  • RuntimeVisibleAnnotations,RuntimeInvisibleAnnotations:注解
  • ConstantValue:常量值
  • RuntimeVisibleTypeAnnotations,RuntimeInvisibleTypeAnnotations:注解

methods_count:方法个数

methods:方法详情

method_info

method_info {
    u2             access_flags;
    u2             name_index;
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

access_flags:同class上的access_flags,可选种类不同

name_index:名称在cp里的索引

descriptor_index:方法描述,含入参和返回值类型,例如

方法:

Object m(int i, double d, Thread t) {...}

描述:

(IDLjava/lang/Thread;)Ljava/lang/Object;

attributes_count:属性个数

attribute_info:属性具体内容,能用在method上的attribute有:

  • Code:除了方法字节码之外,还有max_stack,max_locals表示最大堆栈深度和最大局部变量表长度。exception_table_length和exception_table配合存放异常表,code还携带一组自己的Attribute,具体见CodeAttribute描述。
  • Exceptions:记录方法使用throws关键字声明的可能抛出的异常
  • RuntimeVisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations:方法入参注解。
  • AnnotationDefault,注解类中方法的default值,@interface注解类最终也被编译成class文件。
  • MethodParameters,java8引入,作用未知
  • Synthetic:方法未出现在源码里,是被合成的。
  • Deprecated
  • Signature:当方法入参或返回值是泛型时,方法具有SignatureAttribute,记录泛型信息。
  • RuntimeVisibleAnnotations,RuntimeInvisibleAnnotations:注解
  • RuntimeVisibleTypeAnnotations, RuntimeInvisibleTypeAnnotations:注解

attributes_count:类属性个数

attributes:类具体属性详情,能作为类的attr有以下一些:

  • SourceFile,源文件
  • InnerClasses,内部类,内部记录当前类包含的所有内部类
  • EnclosingMethod,声明该类是匿名内部类
  • SourceDebugExtension,存储用于调试的额外信息
  • BootstrapMethods,存储用于支撑invokedynamic调用的方法
  • Synthetic:类未出现在源码里,是被合成的。
  • Deprecated
  • Signature:泛型类型存在这里
  • RuntimeVisibleAnnotations,RuntimeInvisibleAnnotations:注解
  • RuntimeVisibleTypeAnnotations,RuntimeInvisibleTypeAnnotations:注解

 

class中注解的数据格式:

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:泛型类型索引,指向cp中ConstantUtf8类型常量,记录泛型类全名。

num_element_value_pairs:枚举属性字段个数

element_value_pairs:枚举中的多个属性,kv结构

element_name_index:属性的key索引

element_value:一个元素

 

class中的元素值element_value:

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;
}

tag:value类型,有以下种类,占用1byte枚举:

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 type enum_const_value Not applicable
c Class class_info_index Not applicable
@ Annotation type annotation_value Not applicable
[ Array type array_value Not applicable
  • 其中B到s都是常量索引,占用2bytes,指向cp里的常量内容。
  • e表示的枚举类型,其内容由type_name_index(2bytes)和const_name_index(2bytes)组成。type_name_index指向cp中CONSTANT_Utf8类型常量,记录枚举类型,const_name_index也指向cp中CONSTANT_Utf8类型常量,记录具体的枚举值。
  • c表示类信息,2bytes的class_info_index,指向cp中CONSTANT_Utf8,表示类名。
  • @表示值表示枚举值,其内容还是element_value(正在解析的这个结构)
  • [ 表示数组,包含num_values表示元素个数,values表示多个element_value。

 

class中的codeAttribute:

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; // try开始位置
        u2 end_pc; // try结束位置
        u2 handler_pc; // catch位置
        u2 catch_type; // 能被catch的类型
    } exception_table[exception_table_length]; // 异常表实体(程序发生异常时,查异常表决定如何处理)
    u2 attributes_count; // attribute个数
    attribute_info attributes[attributes_count]; // attribute详情
}

codeAttribute能使用的attribute特别说一下:

1. LineNumberTable,字节码和源码具体行的对应关系。可选的attr,javac命令对应参数lines可以选择是否要将行号信息记录到class文件里,默认情况下javac会执行,详情见《java编译模式》。

2. LocalVariableTable,本地变量表,记录局部变量生命周期,名称,类型,对应frame中局部变量表变量的index。

3. LocalVariableTypeTable,本地变量表的补充,记录局部变量中泛型(Type类型)信息。

4. StackMapTable,栈图,1.6引入,用于优化类型校验。

5. RuntimeVisibleTypeAnnotations, RuntimeInvisibleTypeAnnotations,type注解。

参考:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7

 

你可能感兴趣的:(java,JVM)