美文网首页
Java Class文件

Java Class文件

作者: wangdy12 | 来源:发表于2017-10-31 20:49 被阅读0次

    类文件(.class文件扩展名)是包含Java字节码 ByteCode的文件,可以在Java虚拟机上执行,每个类文件包含了一个类,接口或者模块(Java 9)的定义

    Java程序(.java 文件)可以通过 Java compiler 生成字节码文件,其他基于JVM的语言也都可以通过自己的编译器生成字节码文件,例如Scala,Groovy等

    JVM是与平台无关的,类文件可以在多个平台上执行,这使得相应的语言也与平台无关。

    Class类文件的结构

    类文件由8位字节流组成, 多字节数据使用big-endian的方式存储
    类文件是按照ClassFile结构生成的字节流,字段连续存储,没有任何填充或对齐。
    Class文件格式采是用类C的结构符号表示的伪结构存储数据,有两种数据类型,无符号数(u1,u2,u4,u8)和表(*_info)

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

    Class 文件中涉及类/方法等名称和描述

    名称

    Binary Class and Interface Names
    全限定名称,也叫二进制名称
    例如 Thread正常的二进制名称为 java.lang.Thread ,但是因为一些历史原因,内部格式下,.被替换成了正斜线/,使用CONSTANT_Utf8_info结构(即Utf8编码的字符串常量)表示其为java/lang/Thread

    Unqualified Names
    非限定名称,即简单名称,例如Thread

    描述符

    描述符是表示字段或方法类型(type)的字符串,使用modified UTF-8(UTF-8缩略编码)

    Field Descriptors
    基本数据类型用一个大写字符表示,int对应 I
    对象类型使用一个L加上全限定,末尾加上分号;表示,Object对应Ljava/lang/Object;
    数组每个维度使用一个前置[表示,double[][][]对应[[[D

    Interpretation of field descriptors

    Method Descriptors
    由零个或者多个参数描述符,加上一个返回值描述符组成
    ( {ParameterDescriptor} ) ReturnDescriptor

    Object m(int i, double d, Thread t) {...}
    对应
    (IDLjava/lang/Thread;)Ljava/lang/Object;


    magic & version

    魔数magic number :识别类文件格式,值为0xCAFEBABE
    版本号:M.m(主版本号M,副版本号 m)
    major version从45开始的,每个大版本号向上加1
    JDk1.1.* 支持45.0 到 45.65535
    JDk1.8.* 支持45.0 到 52.65535
    JDk1.k.* 支持主版本号45.0 到 44+k.0 (k>=2)

    常量池

    常量池数目constant_pool_count,数目等于常量表的条目数+1
    常量池constant_pool是一张表,结构化的表示各种字符串常量,类和接口名称,字段名称等,表索引为1到constant_pool_count - 1

    它的用处在于:Java虚拟机指令不依赖于运行时的布局,编译时没有链接这一步,所以指令引用的是constant_pool表中的符号信息

    通用结构

    cp_info {
        u1 tag;
        u1 info[];
    }
    

    表中的每一项都以一个1byte的标志位开头,指明该项的常量类型,之后是紧跟相应的内容,每种类型都有自己的结构

    Constant pool tags

    CONSTANT_Class_info 结构

    CONSTANT_Class_info {
          u1 tag;
          u2 name_index;
    }
    

    tag :CONSTANT_Class (7)
    name_index:是constant_pool中有效的索引,其对应的位置必定是一个CONSTANT_Utf8_info结构,表示类或接口的名称

    CONSTANT_Utf8_info 结构

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

    tag :CONSTANT_Utf8 (1)
    length:长度,限定了最大长度为65535
    bytes[]:Modified UTF-8形式的字符串

    CONSTANT_Fieldref_info 结构
    用于类加载过程中的解析

    CONSTANT_Fieldref_info {
          u1 tag;
          u2 class_index;
          u2 name_and_type_index;
    }
    

    CONSTANT_Fieldref_info, CONSTANT_Methodref_info, CONSTANT_InterfaceMethodref_info三种常量结构相似, tag作为标识,class_index指向相应的类或接口类型信息的常量,name_and_type_index指向CONSTANT_NameAndType_info结构,表示方法或字段的名称和描述符

    访问标志 access_flags

    类或接口的访问权限和属性的标志掩码

    Class access and property modifiers

    自身和父类的信息 this_class / super_class

    u2类型,指向CONSTANT_Class_info的索引,父类的索引可以为0(java.lang.Object没有父类),可以获取对应的类名称

    接口信息 interfaces_count / interfaces[]

    描述了该类扩展的接口信息,interfaces[i] 都是constant_pool表中的CONSTANT_Class_info的索引, 0 ≤ i < interfaces_count,接口的顺序按照源文件中的实现从左向右排列

    字段表

    fields_countfields表中field_info结构的数目
    field_info结构代表了类或接口中所有的字段(类变量class variables(静态变量),实例变量instance variables(类实例中包含的变量)),但是不包含他们的父类或者父接口继承来的字段

    field_info {
        u2 access_flags;
        u2 name_index;
        u2 descriptor_index;
        u2 attributes_count;
        attribute_info attributes[attributes_count];
    }
    
    Field access and property flags

    name_index:指向CONSTANT_Utf8_info结构的索引,表示一个有效的非限定名称
    descriptor_index:指向CONSTANT_Utf8_info结构的索引,表示字段的描述符

    之后是属性信息,存储一些额外的信息,例如对于final static int m = 1,有ConstantValue属性,包含静态变量的赋值信息。

    方法表

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

    同字段表类似,访问标识有部分不同


    Method access and property flags

    方法中的Java代码,经过编译器,编译成字节码格式之后,存放在方法的属性表内的Code属性内
    方法表中可能会有编译器自己添加的方法,例如<init><clinit>

    属性表

    ClassFile, field_info, method_info, and Code_attribute 结构中,都含有属性
    Java 9共有26种预定义的属性

    Predefined class file attributes

    每个属性的名称用CONSTANT_Utf8_info表示,属性的结构如下

    attribute_info {
        u2 attribute_name_index;
        u4 attribute_length;
        u1 info[attribute_length];
    }
    

    Code属性

    是可变长度的属性,包含了一个方法的JVM指令和辅助信息
    nativeabstract类没有Code属性

    //Code 属性的结构
    Code_attribute {
        u2 attribute_name_index; //对应一个`CONSTANT_Utf8_info `索引,内容是Code
        u4 attribute_length;
        u2 max_stack; //operand stack 操作数栈的最大深度
        u2 max_locals;//局部变量数组的长度
        u4 code_length; //长度小于65536
        u1 code[code_length];//字节码指令
        u2 exception_table_length;
        {   u2 start_pc;
            u2 end_pc; //在code数组中的起点和终点[start_pa, end_pc)
            u2 handler_pc; //异常处理对应的字节码起始位置
            u2 catch_type;// 是常量池中 CONSTANT_Class_info的索引,表示捕获的异常类型,为0则处理任何异常 
        } exception_table[exception_table_length];//异常表
        u2 attributes_count;
        attribute_info attributes[attributes_count];
    }
    

    Exception属性

    声明所有的受查异常(checked exception,不是派生于ErrorRuntimeException的其他所有异常)

    Exceptions_attribute {
        u2 attribute_name_index; //索引指向`CONSTANT_Utf8_info `表示"Exceptions"
        u4 attribute_length;
        u2 number_of_exceptions;
        u2 exception_index_table[number_of_exceptions]; //索引指向`CONSTANT_Class_info`,表示受查异常的类型
    }
    

    LineNumberTable

    出现在Code属性的attributes表中,显示code字节码和相应java源文件的行号
    用于调试,以及抛出异常时,显示出错的行号

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

    LocalVariableTypeTable

    局部变量表,出现在Code属性的attributes表中,用来在调试过程中描述局部变量的具体类型

    LocalVariableTable_attribute {
        u2 attribute_name_index;
        u4 attribute_length;
        u2 local_variable_table_length;
        {   u2 start_pc; //对应局部变量的开始位置
            u2 length;//作用域[start_pc, start_pc + length)
            u2 name_index;//名称
            u2 signature_index;//签名信息,和描述符类似,保留了泛型类型
            u2 index;//局部变量在当前栈帧局部变量表中的位置索引
        } local_variable_table[local_variable_table_length];
    }
    
    函数示例

    SourceFile

    记录源码文件的名称

    Signature

    Signature_attribute {
        u2 attribute_name_index; // "Signature"
        u4 attribute_length;  //必定是2
        u2 signature_index; //对应CONSTANT_Utf8_info,表示类,接口,构造器,方法,字段的签名
    }
    

    Java字节码的方法的特征签名,包含返回值和受查异常表(详细信息,参考jvms9 4.7.9.1)
    [TypeParameters] ( {JavaTypeSignature} ) Result {ThrowsSignature}

    InnerClass

    记录内部类和宿主类之间的关联

    InnerClasses_attribute {
        u2 attribute_name_index; 
        u4 attribute_length;
        u2 number_of_classes;
        {   u2 inner_class_info_index;//内部类或接口信息CONSTANT_Class_info
            u2 outer_class_info_index;//外部类或接口信息CONSTANT_Class_info
            u2 inner_name_index;//内部类的名称CONSTANT_Class_info,匿名内部类名称为0
            u2 inner_class_access_flags;
        } classes[number_of_classes];
    }
    
    Nested class access and property flags

    ConstantValue

    静态变量相关的一个定长属性

    ConstantValue_attribute {
          u2 attribute_name_index;
          u4 attribute_length;
          u2 constantvalue_index;
    }
    
    常量池中对应字段的类型

    javap

    反编译Class文件,没有选项时输出包,类里的protected和public字段和方法

    用法:javap [options] classfile

    • -verbose 打印细节,可以查看常量表,栈大小,各方法的 locals 及 args 数等
    • -p -private 显示所有的类和成员
    • -c 输出类中各方法的 Java 字节码的指令
    • -s signatures,输出内部类型签名

    Reference:
    Java Language and Virtual Machine Specifications
    The Java® Virtual Machine Specification Java SE 9 Edition

    相关文章

      网友评论

          本文标题:Java Class文件

          本文链接:https://www.haomeiwen.com/subject/yrdkpxtx.html