服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

java入门:java类文件详解

一、什么是java类文件
    java类文件是java程序的二进制表示形式。每一个类文件代表一个类或者接口。不可能在一个类文件中放入多个类或者接口。这样就使得无论类文件是在哪一种平台上生成,都可以在任何主机上执行。
    虽然类文件是java体系结构的一部分,但是他并不是与java语言不可分的。你可以将其他语言的程序编译为类文件,也可以将java程序文件编译为其他二进制形式。
java类文件是一个基于8-bit字节的二进制流。数据块顺序的、无分割符的、big-endian的形式存储。
二、类文件的内容
    java的类文件中包含了所有java虚拟机所需要的关于类和接口的信息。所有类文件中的信息都以以下的四种基本类型的存储:
    table 6-1. class file "primitive types"
    u1    a single unsigned byte
    u2    two unsigned bytes
    u4    four unsigned bytes
    u8    eight unsigned bytes
    类文件中的主要部分以表6-2的顺序存储:
    table 6-2. format of a classfile table
    type&    #9;name    count
    u4    magic    1
    u2    minor_version    1
    u2    major_version    1
    u2    constant_pool_count    1
    cp_info    constant_pool    constant_pool_count-1
    u2    access_flags    1
    u2    this_class    1
    u2    super_class    1
    u2    interfaces_count    1
    u2    interfaces    interfaces_count
    u2    fields_count    1
    field_info    fields    fields_count
    u2    methods_count    1
    method_info    methods    methods_count
    u2    attributes_count    1
    attribute_info    attributes    attributes_count
    1、魔术编码(magic)
    每一个java类文件的开头四个字节都是魔术编码(oxcafebabe)。通过魔术编码可以很容易识别类文件。
    2、副版本号和主版本号(minor_version and major_version)
    剩下的四个字节是副版本号和主版本号。但java技术在进化时,一些新的特性可能会被加入到类文件中。每一次类文件格式的变化,都会相应的改变版本号。虚 拟机通过版本号来识别自己能够处理的类文件。java虚拟机往往只能处理一个给定的主版本号和其下的一些副版本号。虚拟机必须拒绝那些不再处理范围内的类 文件。
    3、常量个数和常量池(constant_pool_count and constant_pool)
    接下来的就是常量池,常量池中包含了哪些被类或者接口访问过的常量,比如:字符串,常量(final variable values),类名,方法名。常量池作为一个列表存储。列表中常量的个数就是之前保存的“constant_pool_count”。
    很多常量池中的常量都引用了常量池中的其他常量,那些引用常量池常量的引用最终也会转换为对常量池中常量的直接引用。虽然常量列表中的索引是从1开始的,但是常量个数还是包含了0,比如一个常量列表中有15个常量,那么它的常量个数就为16。
    每一个常量开头都会有一个标志,以表示他的类型。当虚拟机读取这个标志时,就会知道这个常量的具体类型了。表6-3列举了这些标志:
    table 6-3. constant pool tags
    entry type    tag value    description
    constant_utf8    1    a utf-8 encoded unicode string
    constant_integer    3    an int literal value
    constant_float    4    a float literal value
    constant_long    5    a long literal value
    constant_double    6    a double literal value
    constant_class    7    a symbolic reference to a class or interface
    constant_string    8    a string literal value
    constant_fieldref    9    a symbolic reference to a field
    constant_methodref    10    a symbolic reference to a method declared in a class
    constant_interfacemethodref    11    a symbolic reference to a method declared in an interface
    constant_nameandtype    12    part of a symbolic reference to a field or method
    表6-3中的每一个标志都会有一个相应的表格,用来描述这个标志的所表示的一些详细信息,这些对应的标志都会以标志名+_info来结尾。比如constant_class标志对应的就是constant_class_info。
    常量池在程序的动态链接中扮演了很重要的角色。除了上边所说的各种常量值以外,常量池中包含了一下三种符号引用:类和接口的全名,字段名和描述符,方法名 和描述符。一个字段是一个类或者接口中的实例或者类变量,字段描述符是字段的类型。方法的描述符是方法和返回值和参数的个数、顺序和类型。在虚拟机将这个 类或者接口链接到其他类或者接口时用到这些全名。因为类文件不包含任何关于内存结构的信息,所以这个链接只能以符号引用的形式存在。虚拟机在执行时将这些 符号引用转换为实际的地址。具体的信息参见第八章“the linking model”。
    4、访问标志(access_flags)
    紧接在常量池后面的两个字节就是访问标志,表示这个类或者接口的几方面信息,他有如下几种值:
    table 6-4. flag bits in the access_flags item of classfile tables
    flag name    value    meaning if set    set by
    acc_public    0x0001    type is public    classes and interfaces
    acc_final    0x0010    class is final    classes only
    acc_super    0x0020    use new    invokespecial semanticsclasses and interfaces
    acc_interface    0x0200    type is an interface, not a class    all interfaces, no classes
    acc_abstract    0x0400    type is abstract    all interfaces, some classes
    acc_super标志是为了兼容以前sun的老式的编译器。所有没有使用的访问标志,必须设置为0。
    5、类名(this_class)
    接下来的两个字节保存了一个常量池的索引。这个常量池中的实体必须是constant_clss_into类型的,他包含了标志和名字索引。标志就是 constatn_class,那个名字索引应该是一个保存了这个类或者接口全名的constant_utf8_info类型的索引。
    6、父类(super_class)
    this_class之后的就是两个字节的super_class,他也是一个常量池的索引,其中保存了父类的全名,处理this_class一样。当父 类是java.lang.object时,super_class都应该是0。对于接口super_class都是0。
    7、(interfaces_count and interfaces)
    interfaces_count中保存了父接口的个数,interfaces中以数组形式保存了一些常量池的索引。每一个索引都指向了一个 constant_class_info的常量,其中保存了每一个父接口的全名。这个数组的顺序就是父接口出现在在implements、extends 语句中从左到右的顺序。
    8、(fields_count and fields)
    字段被保存在一个field_info的列表中,fields_count是这个列表的长度。field_info列表中保存的只是类或者接口中的申明的变量,从父类或者父接口中继承的字段不保存在这里。
每一个field_info表中的一条都描述了一个字段的信息,包括:字段名,描述符,访问权限。如果一个字段被申明为final,那么这个字段的信息即会保存在field_info表中,也会保存在常量池中。
    9、(methods_count and methods)
    方法的信息都保存在method_info表中,mehtods_count是表的长度。method_info表中只保存类或者接口中申明的方法,不保存从父类或者接口中继承的方法。
method_info 表中保存了方法名和描述符(返回值和参数类型)。如果不是抽象方法,还会保存用于堆栈的大小(保存本地变量用的)、操作数堆栈的最大值、捕捉的异常列表、 方法的字节码、可选的行号和本地变量表。如果方法抛出一些被检查的异常,method_info还会包含一个被检查异常的列表。
    10、(attributes_count and attributes)
    类文件中最后的就是属性个数和atribute_info列表。atribute_info表中保存了一些指向常量池中constant_utf8_info的索引,其中保存了属性的名字。java虚拟机规范中定义了两种类型的属性:源代码和内部类。

三、特定字符串(special strings)
    常量池中的字符引用包含三种特定字符串:全限定名,简单名,描述符。一个类或者接口的所有字符引用都必须包含一个全限定名。每一个字段或者方法都有一个简 单名和描述符作为全限定名的补充。这些特定字符串用来表示文件中定义的类和接口,包换类名,父类名,父接口名,每个字段和方法的简单名和描述符。
    1、全名(fully qualified names)
    当常量池中引用了类和接口时,就会提供这个类或者接口的权限定名,比如java.lang.object。
    2、简单名(simple names)
    字段和方法都以简单名的形式保存在常量池中。比如常量池中有一个java.lang.object类的string tostring()方法的引用,就会保存“tostring”;java.lang.system类的java.io.printstream out字段,被保存为“out”。
    3、描述符(descripters)
    字段和方法的字符引用都会包含一个描述符。字段的描述符提供了字段的类型。方法的描述符提供了方法的返回值、参数个数、参数类型。所有描述符得类型列表:
    fielddescriptor:
    fieldtype
    componenttype:
    fieldtype
    fieldtype:
    basetype
    objecttype
    arraytype
    basetype:
    terminal    type
    b    byte
    c    char
    d    double
    f    float
    i    int
    j    long
    s    short
    z    boolean
    objecttype:
    l<classname>;
    arraytype:
    [ componenttype
    parameterdescriptor:
    fieldtype
    methoddescriptor:
    ( parameterdescriptor* ) returndescriptor
    returndescriptor:
    fieldtype
    v
    table 6-6. examples of field descriptors
    descriptor    field declaration
    i    int i;
    [[j    long[][] windingroad;
    [ljava/lang/object;    java.lang.object[] stuff;
    ljava/util/hashtable;    java.util.hashtable ht;
    [[[z    boolean[][][] isready;
    table 6-7. examples of method descriptors
    descriptor    method declaration
    ()i    int getsize();
    ()ljava/lang/string;    string tostring();
    ([ljava/lang/string;)v    void main(string[] args);
    ()v    void wait()
    (ji)v    void wait(long timeout, int nanos)
    (ziljava/lang/string;ii)z    boolean regionmatches(boolean ignorecase, int tooffset, string other, int ooffset, int len);
    ([bii)i    int read(byte[] b, int off, int len);
四、常量池
    常量池被组织成为一个cp_info类型的列表,表6-8显示了cp_info表的结构
    table 6-8. general form of a cp_info table
    type    name     count
    u1    tag    1
    u1    info     depends on tag value
    1、the constant_utf8_info table
    2、the constant_integer_info table
    3、the constant_float_info table
    4、the constant_long_info table
    5、the constant_double_info table
    6、the constant_class_info table
    7、the constant_string_info table
    8、the constant_fieldref_info table
    9、the constant_methodref_info table
    10、the comstant_interfacemethodref_info table
    11、the constant_nameandtype_info table
五、fields
六、methods
七、attributes

扫描关注微信公众号