• java class 文件格式解析


    前言

    大约5年前,想研究javaassistant,cglib等字节码操作的相关类库,来对class进行增强,当要到要操作字节码的时候,发现无法继续下去了,看不懂,只能放弃。
    学习jvm字节码,需要理解class的组成方式,对汇编,操作栈比较了解,无奈,只好重新学习编译原理,汇编等知识,再来看jvm规范,现在理解起来,容易很多了。

    Class文件规范

    编译后被 Java 虚拟机所执行的代码使用了一种平台中立(不依赖于特定硬件及操作系统的)
    的二进制格式来表示,并且经常(但并非绝对)以文件的形式存储,因此这种格式被称为 Class
    文件格式。Class 文件格式中精确地定义了类与接口的表示形式,包括在平台相关的目标文件格
    式中一些细节上的惯例

    相关文档
    https://docs.oracle.com/javase/specs/jvms/se15/html/jvms-4.html

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

    下面,我们开始解析每个字段是如何标识出来的
    其中 u4, u2 代表什么意思
    u 表示无符号数 后面的数字 表示 占用多少字节
    u4 占用4个字节
    u2 占用2个字节

    1. magic 占用4个字节,(ca fe ba be )

    image

    1. minor_version 子版本号 ,2个字节数字
      image

    2. major_version 主版本好 2个字节的数字

    image

    1. constant_pool_count 常量池数目 2个字节的数字

    image

    1. constant_pool[constant_pool_count-1] 常量池数组

    image

    1. access_flags 访问标识 2个字节数字
    2. this_class class名称的索引,
    3. super_class 超类的名称索引
    4. interfaces_count 接口的数目
    5. interfaces[interfaces_count] 接口的数组
    6. fields_count 字段数目
    7. fields[fields_count] 字段的数组
    8. methods_count 方法的数目
    9. methods[methods_count] 方法的数组
    10. attributes_count 属性的数目
    11. attributes[attributes_count] 属性的数组

    如何自己动手解一个class文件

    相信大部分第一次看到上面的协议时候,能看懂,但是要自己动手解析出每个字段的含义出来,
    就无法下手了,

    1. 读取class文件
     FileInputStream in= new FileInputStream("d:/my.class");
    
    1. 读取 magic ,(magic u4 占用4个字节)
     byte[] bytes=new byte[4];
           in.read(bytes);
    
    1. 读取 minor_version u2 占用2个字节
     byte[] minorByte=new byte[2];
           in.read(minorByte);
    
    1. 读取 major_version u2 占用2个字节
     byte[] majorVersion=new byte[2];
           in.read(majorVersion);
    

    看到上面的解析,是否明白了,其实还是很有规律的,只要你认真看协议文档(要看好多遍才行)

    最终解析class 文档就是这样的

    ClassFile classFile = new ClassFile();
    
            PcBufferInputStream in = new PcBufferInputStream(new FileInputStream(fileName));
            classFile.setMagic(readMagic(in));
            classFile.setMinorVersion(readMinorVersion(in));
            classFile.setMajorVersion(readMajorVersion(in));
            classFile.setConstantPoolCount(readConstantPoolCount(in));
            classFile.setCpInfo(readCpInfo(in));
            classFile.setAccessFlags(readAccessFlags(in));
            classFile.setThisClass(readThisClass(in));
            classFile.setSuperClass(readSuperClass(in));
            classFile.setInterfacesCount(readInterfacesCount(in));
            // u2 interfaces interfaces_count
            classFile.setInterfaces(readInterfaces(in));
            // u2 fields_count
            classFile.setFieldsCount(readFieldsCount(in));
            // field_info fields fields_count
            classFile.setFields(readFields(in));
            // u2 methods_count 1
            // method_info methods methods_count
            classFile.setMethodsCount(readMethodsCount(in));
            classFile.setMethods(readMethods(in));
            // u2 attribute_count 1
            classFile.setAttributeCount(readAttributeCount(in));
            // attribute_info attributes attributes_count
            classFile.setAttributes(readAttributes(in));
            classFile.setPcRecord(recordMap);
            return classFile;
    

    java class 解析源码开源地址

    https://gitee.com/venus-suite/java-classViewer

    如果喜欢,欢迎stars 哦

  • 相关阅读:
    Java集合:Map集合的几种常用遍历方式
    设计模式之观察者模式
    java毕业生设计校园讲座管理计算机源码+系统+mysql+调试部署+lw
    高薪程序员&面试题精讲系列131之Eureka如何实现高可用?自我保护机制是怎么回事?
    笔记二:odoo搜索、筛选和分组
    统一网关Gateway、路由断言工厂、路由过滤器及跨域问题处理
    5. 【哈夫曼树】定义、构造、编码
    如何使能512个virtio_blk设备
    【毕业设计】后端实现——各个支付平台保存的账单分析与导入合并
    文生视频开源产品的一些调研(一)
  • 原文地址:https://www.cnblogs.com/tomj2ee/p/16153238.html