JVM学习笔记之class文件

class文件




实验类:
package core;

public class Foo{

    int m = 6;

    public Foo{
        this.show();
    }

    void show (){ System.out.println("father"); }
}




反汇编:

图1


涉及到的JVM指令:
aload_<n>                    从局部变量表加载一个reference类型值到操作数栈中;
invokespecial                调用实例方法,专门用来调用父类方法、私有方法和实例初始化方法;
bipush                          将一个byte类型数据入栈;
putfield                          设置对象字段;
invokevirtual                  调用实例方法,依据实例的类型进行分派;
return                            方法中返回void;
getstatic                        获取类的静态字段值;
ldc                                  从运行时常量池中提取数据并压入操作数栈;





vim -b Foo.class
:%! xxd

图2




ClassFile文件结构:

ClassFile{
    u4                        magic;                                                                        // Magic 魔数,固定值 0xCAFEBABE
    u2                        minor_version;                                                          // 副版本号
    u2                        major_version;                                                           // 主版本号
    u2                        constant_pool_count;                                                // 常量池容量计数器
    cp_info                constant_pool;                                                           // 常量池
    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];                                    // 属性表

}

根据Java虚拟机规范,Class文件格式采用类似C语言结构体的伪结构存储数据,这种结构中只有两种数据类型:无符号数和表。
        无符号数属于基本的数据类型,以u1、u2、u4、u8来分别代表1个字节、2个字节、4个字节、8个字节的无符号数,无符号数可以用来描述
数字、索引引用、数量值或按照UTF-8编码构成字符串值。
        表是由多个无符号数或其他表作为数据项构成的复合数据类型,所有表都以"_info"结尾。表用于描述有层次关系的复合结构的数据,整个Class
文件本质上就是一张表。
        无论是无符号数还是表,当需要描述同一类型但数量不定的多个数据时,经常会使用一个前置的容器计数器加若干个连续的数据项的形式,这时
称这一系列连续的某一类型的数据为某一类型的集合。
        
        魔数(1~4字节):确定该文件是否为一个能被虚拟机接受的Class文件。
        次版本号(5~6字节):
        主版本号(7~8字节):
        常量池容量计数器(9~10字节):常量池中常量的数量;
        常量池:常量池中主要存放两大类常量:字面量(文本字符串、声明为final的常量值等)、符号引用(类和接口的全限定名、字段的名称和
                      描述符、方法的名称和描述符);
                      常量池共有14种常量类型且均有自己的结构,因篇幅限制不赘述。
        访问标志(2个字节):用于识别一些类或者接口层次的访问信息(这个Class是类还是接口;是否定义为public类型;是否定义为abstract
                                             类型;是否被声明为final等)。
        类索引(2个字节):用于确定类的全限定名;
        父类索引(2个字节):用于确定类的父类的全限定名;
        接口计数器(2个字节):用来描述类实现了哪些接口;
        接口表(2个字节):
        字段计数器(2个字节):
        字段表:
        方法计数器(2个字节):
        方法表:
        属性计数器(2个字节):
        属性表:







参考:《Java虚拟机规范》、《深入Java虚拟机》


注:


猜你喜欢

转载自blog.csdn.net/ggf123456789/article/details/53329205
今日推荐