JVM字节码常量池解析

JVM字节码常量池解析

前言

最近写J2ME深感各种java反编译不得我心,决定自己尝试写一个自己的java反编译,第一步实现javap。现在把字节码的常量池的解析代码分享出来。

常量池类型

前面已经分析过了,现在直接贴代码

cpp 复制代码
//	§4.4.1
#define CONSTANT_Class    7
//	§4.4.2
#define CONSTANT_Fieldref    9
//	§4.4.2
#define CONSTANT_Methodref    10
//	§4.4.2
#define CONSTANT_InterfaceMethodref    11
//	§4.4.3
#define CONSTANT_String    8
//	§4.4.4
#define CONSTANT_Integer    3
//	§4.4.4
#define CONSTANT_Float    4
//	§4.4.5
#define CONSTANT_Long    5
//	§4.4.5
#define CONSTANT_Double    6
//	§4.4.6
#define CONSTANT_NameAndType    12
//	§4.4.7
#define CONSTANT_Utf8    1
//	§4.4.8
#define CONSTANT_MethodHandle    15
//	§4.4.9
#define CONSTANT_MethodType    16
//	§4.4.10
#define CONSTANT_Dynamic    17
//	§4.4.10
#define CONSTANT_InvokeDynamic    18
//	§4.4.11
#define CONSTANT_Module    19
//	§4.4.12
#define CONSTANT_Package    20

代码定义

ConstPool.h

3.1常量池基类定义

cpp 复制代码
// ==================== 常量池基类定义 ====================

/**
 * 常量池项基类 - 所有常量池项的抽象基类
 * 定义了常量池项的基本接口和公共属性
 */
class constant_pool_info {
public:
    u1 tag; // 常量池项类型标识

    virtual ~constant_pool_info() = default;

    // 获取常量池项的字符串表示
    virtual std::string toString() const = 0;

    // 获取常量池项的大小(字节)
    virtual size_t getSize() const = 0;

    // 验证常量池项的有效性
    virtual bool validate() const = 0;

    // 从文件流中读取数据
    virtual void readFrom(std::istream& file) = 0;
};

3.2 CONSTANT_Class_info (tag=7) - 类或接口引用

cpp 复制代码
/**
 * CONSTANT_Class_info (tag=7) - 类或接口引用
 * 表示一个类或接口的符号引用
 */
class CONSTANT_Class_info : public constant_pool_info {
public:
    u2 name_index; // 指向常量池中UTF8字符串的索引,表示类的全限定名

    CONSTANT_Class_info() { tag = CONSTANT_Class; }

    std::string toString() const override;
    size_t getSize() const override { return 3; } // 1字节tag + 2字节name_index
    bool validate() const override;
    void readFrom(std::istream& file) override;
};

3.3 CONSTANT_Fieldref_info (tag=9) - 字段引用

cpp 复制代码
/**
 * CONSTANT_Fieldref_info (tag=9) - 字段引用
 * 表示对一个字段的符号引用
 */
class CONSTANT_Fieldref_info : public constant_pool_info {
public:
    u2 class_index;            // 指向类或接口的CONSTANT_Class_info索引
    u2 name_and_type_index;    // 指向字段名和类型的CONSTANT_NameAndType_info索引

    CONSTANT_Fieldref_info() { tag = CONSTANT_Fieldref; }

    std::string toString() const override;
    size_t getSize() const override { return 5; } // 1字节tag + 4字节索引
    bool validate() const override;
    void readFrom(std::istream& file) override;
};

3.4 CONSTANT_Methodref_info (tag=10) - 方法引用

cpp 复制代码
/**
 * CONSTANT_Methodref_info (tag=10) - 方法引用
 * 表示对一个方法的符号引用
 */
class CONSTANT_Methodref_info : public constant_pool_info {
public:
    u2 class_index;            // 指向类或接口的CONSTANT_Class_info索引
    u2 name_and_type_index;    // 指向方法名和类型的CONSTANT_NameAndType_info索引

    CONSTANT_Methodref_info() { tag = CONSTANT_Methodref; }

    std::string toString() const override;
    size_t getSize() const override { return 5; }
    bool validate() const override;
    void readFrom(std::istream& file) override;
};

3.5 CONSTANT_InterfaceMethodref_info (tag=11) - 接口方法引用

cpp 复制代码
/**
 * CONSTANT_InterfaceMethodref_info (tag=11) - 接口方法引用
 * 表示对一个接口方法的符号引用
 */
class CONSTANT_InterfaceMethodref_info : public constant_pool_info {
public:
    u2 class_index;            // 指向接口的CONSTANT_Class_info索引
    u2 name_and_type_index;    // 指向方法名和类型的CONSTANT_NameAndType_info索引

    CONSTANT_InterfaceMethodref_info() { tag = CONSTANT_InterfaceMethodref; }

    std::string toString() const override;
    size_t getSize() const override { return 5; }
    bool validate() const override;
    void readFrom(std::istream& file) override;
};

3.6 CONSTANT_String_info (tag=8) - 字符串引用

cpp 复制代码
/**
 * CONSTANT_String_info (tag=8) - 字符串引用
 * 表示对一个字符串字面量的引用
 */
class CONSTANT_String_info : public constant_pool_info {
public:
    u2 string_index; // 指向CONSTANT_Utf8_info的索引,表示字符串内容

    CONSTANT_String_info() { tag = CONSTANT_String; }

    std::string toString() const override;
    size_t getSize() const override { return 3; }
    bool validate() const override;
    void readFrom(std::istream& file) override;
};

3.7 CONSTANT_Integer_info (tag=3) - 整型常量

cpp 复制代码
/**
 * CONSTANT_Integer_info (tag=3) - 整型常量
 * 表示4字节int类型的常量值
 */
class CONSTANT_Integer_info : public constant_pool_info {
public:
    u4 bytes; // 整数值,按大端序存储

    CONSTANT_Integer_info() { tag = CONSTANT_Integer; }

    std::string toString() const override;
    size_t getSize() const override { return 5; }
    bool validate() const override;
    void readFrom(std::istream& file) override;

    // 获取整数值
    int32_t getValue() const { return static_cast<int32_t>(bytes); }
};

3.8 CONSTANT_Float_info (tag=4) - 浮点常量

cpp 复制代码
/**
 * CONSTANT_Float_info (tag=4) - 浮点常量
 * 表示4字节float类型的常量值
 */
class CONSTANT_Float_info : public constant_pool_info {
public:
    u4 bytes; // 浮点数值,按IEEE 754格式存储

    CONSTANT_Float_info() { tag = CONSTANT_Float; }

    std::string toString() const override;
    size_t getSize() const override { return 5; }
    bool validate() const override;
    void readFrom(std::istream& file) override;

    // 获取浮点数值
    float getValue() const {
        auto val = bytes;
        return *reinterpret_cast<float*>(&val);
    }
};

3.9 CONSTANT_Long_info (tag=5) - 长整型常量

cpp 复制代码
/**
 * CONSTANT_Long_info (tag=5) - 长整型常量
 * 表示8字节long类型的常量值
 * 注意:此类型在常量池中占用两个位置
 */
class CONSTANT_Long_info : public constant_pool_info {
public:
    u4 high_bytes; // 高32位
    u4 low_bytes;  // 低32位

    CONSTANT_Long_info() { tag = CONSTANT_Long; }

    std::string toString() const override;
    size_t getSize() const override { return 9; } // 在文件中占9字节,但在常量池中占两个位置
    bool validate() const override;
    void readFrom(std::istream& file) override;

    // 获取长整数值
    int64_t getValue() const {
        return (static_cast<int64_t>(high_bytes) << 32) | low_bytes;
    }
};

3.10 CONSTANT_Double_info (tag=6) - 双精度浮点常量

cpp 复制代码
/**
 * CONSTANT_Double_info (tag=6) - 双精度浮点常量
 * 表示8字节double类型的常量值
 * 注意:此类型在常量池中占用两个位置
 */
class CONSTANT_Double_info : public constant_pool_info {
public:
    u4 high_bytes; // 高32位
    u4 low_bytes;  // 低32位

    CONSTANT_Double_info() { tag = CONSTANT_Double; }

    std::string toString() const override;
    size_t getSize() const override { return 9; }
    bool validate() const override;
    void readFrom(std::istream& file) override;

    // 获取双精度浮点数值
    double getValue() const {
        auto val = (static_cast<long long>(high_bytes) << 32) | low_bytes;
        return *reinterpret_cast<double*>(&val);
    }
};

3.11 CONSTANT_NameAndType_info (tag=12) - 名称和类型

cpp 复制代码
/**
 * CONSTANT_NameAndType_info (tag=12) - 名称和类型
 * 表示字段或方法的名称和描述符
 */
class CONSTANT_NameAndType_info : public constant_pool_info {
public:
    u2 name_index;       // 指向名称的CONSTANT_Utf8_info索引
    u2 descriptor_index; // 指向描述符的CONSTANT_Utf8_info索引

    CONSTANT_NameAndType_info() { tag = CONSTANT_NameAndType; }

    std::string toString() const override;
    size_t getSize() const override { return 5; }
    bool validate() const override;
    void readFrom(std::istream& file) override;
};

3.12 CONSTANT_Utf8_info (tag=1) - UTF-8字符串

cpp 复制代码
/**
 * CONSTANT_Utf8_info (tag=1) - UTF-8字符串
 * 表示UTF-8编码的字符串,常量池中实际的字符串存储
 */
class CONSTANT_Utf8_info : public constant_pool_info {
public:
    u2 length; // 字符串长度(字节数)
    u1 *bytes; // UTF-8编码的字节数组

    CONSTANT_Utf8_info() {
        tag = CONSTANT_Utf8;
        bytes = nullptr;
        length = 0;
    }

    ~CONSTANT_Utf8_info() override {
        delete[] bytes;
    }

    // 拷贝构造函数和赋值操作符
    CONSTANT_Utf8_info(const CONSTANT_Utf8_info& other);
    CONSTANT_Utf8_info& operator=(const CONSTANT_Utf8_info& other);

    std::string toString() const override;
    size_t getSize() const override { return 3 + length; }
    bool validate() const override;
    void readFrom(std::istream& file) override;

    // 获取字符串
    std::string getString() const;

    // 设置字符串
    void setString(const std::string& str);
};

3.13 CONSTANT_MethodHandle_info (tag=15) - 方法句柄

cpp 复制代码
/**
 * CONSTANT_MethodHandle_info (tag=15) - 方法句柄
 * Java 7引入,表示方法句柄,用于动态语言支持
 */
class CONSTANT_MethodHandle_info : public constant_pool_info {
public:
    u1 reference_kind;   // 引用类型 (1-9)
    u2 reference_index;  // 引用索引,指向常量池中的一项

    CONSTANT_MethodHandle_info() { tag = CONSTANT_MethodHandle; }

    std::string toString() const override;
    size_t getSize() const override { return 4; }
    bool validate() const override;
    void readFrom(std::istream& file) override;
};

3.14 CONSTANT_MethodType_info (tag=16) - 方法类型

cpp 复制代码
/**
 * CONSTANT_MethodType_info (tag=16) - 方法类型
 * Java 7引入,表示方法类型,用于动态语言支持
 */
class CONSTANT_MethodType_info : public constant_pool_info {
public:
    u2 descriptor_index; // 指向方法描述符的CONSTANT_Utf8_info索引

    CONSTANT_MethodType_info() { tag = CONSTANT_MethodType; }

    std::string toString() const override;
    size_t getSize() const override { return 3; }
    bool validate() const override;
    void readFrom(std::istream& file) override;
};

3.15 CONSTANT_Dynamic_info (tag=17) - 动态调用点

cpp 复制代码
/**
 * CONSTANT_Dynamic_info (tag=17) - 动态调用点
 * Java 11引入,用于更高级的动态语言特性
 */
class CONSTANT_Dynamic_info : public constant_pool_info {
public:
    u2 bootstrap_method_attr_index; // 指向BootstrapMethods属性的索引
    u2 name_and_type_index;         // 指向名称和类型的CONSTANT_NameAndType_info索引

    CONSTANT_Dynamic_info() { tag = CONSTANT_Dynamic; }

    std::string toString() const override;
    size_t getSize() const override { return 5; }
    bool validate() const override;
    void readFrom(std::istream& file) override;
};

3.16 CONSTANT_InvokeDynamic_info (tag=18) - 调用动态

cpp 复制代码
/**
 * CONSTANT_InvokeDynamic_info (tag=18) - 调用动态
 * Java 7引入,用于invokedynamic指令
 */
class CONSTANT_InvokeDynamic_info : public constant_pool_info {
public:
    u2 bootstrap_method_attr_index; // 指向BootstrapMethods属性的索引
    u2 name_and_type_index;         // 指向方法名和类型的CONSTANT_NameAndType_info索引

    CONSTANT_InvokeDynamic_info() { tag = CONSTANT_InvokeDynamic; }

    std::string toString() const override;
    size_t getSize() const override { return 5; }
    bool validate() const override;
    void readFrom(std::istream& file) override;
};

3.17 CONSTANT_Module_info (tag=19) - 模块名

cpp 复制代码
/**
 * CONSTANT_Module_info (tag=19) - 模块名
 * Java 9引入,用于模块系统
 */
class CONSTANT_Module_info : public constant_pool_info {
public:
    u2 name_index; // 指向模块名的CONSTANT_Utf8_info索引

    CONSTANT_Module_info() { tag = CONSTANT_Module; }

    std::string toString() const override;
    size_t getSize() const override { return 3; }
    bool validate() const override;
    void readFrom(std::istream& file) override;
};

3.18 CONSTANT_Package_info (tag=20) - 包名

cpp 复制代码
/**
 * CONSTANT_Package_info (tag=20) - 包名
 * Java 9引入,用于模块系统
 */
class CONSTANT_Package_info : public constant_pool_info {
public:
    u2 name_index; // 指向包名的CONSTANT_Utf8_info索引

    CONSTANT_Package_info() { tag = CONSTANT_Package; }

    std::string toString() const override;
    size_t getSize() const override { return 3; }
    bool validate() const override;
    void readFrom(std::istream& file) override;
};

实现代码与管理代码

4.1工厂管理工具类

cpp 复制代码
/**
 * 常量池工厂类 - 根据tag创建对应的常量池对象
 * 使用工厂模式,提供统一的创建接口
 */
class ConstantPoolFactory {
public:
    /**
     * 根据tag值创建对应的常量池对象
     * @param tag 常量池项类型标识
     * @return 对应的常量池对象指针,如果tag无效则返回nullptr
     */
    static constant_pool_info* createConstant(u1 tag);

    /**
     * 检查tag是否为有效的常量池类型
     * @param tag 要检查的tag值
     * @return 是否有效
     */
    static bool isValidTag(u1 tag);

    /**
     * 获取常量池类型的名称
     * @param tag 常量池类型标识
     * @return 类型名称字符串
     */
    static std::string getConstantTypeName(u1 tag);

    /**
     * 检查该常量池类型是否在常量池中占用两个位置
     * @param tag 常量池类型标识
     * @return 是否占用两个位置
     */
    static bool takesTwoSlots(u1 tag);
};

这里的实现逻辑比较简单switch或者if判断tag的类型就行

cpp 复制代码
constant_pool_info *ConstantPoolFactory::createConstant(u1 tag) {
    switch (tag) {
        case CONSTANT_Class:
            return new CONSTANT_Class_info();
        case CONSTANT_Fieldref:
            return new CONSTANT_Fieldref_info();
        case CONSTANT_Methodref:
            return new CONSTANT_Methodref_info();
        case CONSTANT_InterfaceMethodref:
            // 省略机械重复性代码

4.2 具体常量实现代码

贴两个示例

cpp 复制代码
// CONSTANT_Long_info
void CONSTANT_Long_info::readFrom(std::istream& file) {
    high_bytes = IoUtil::readU4(file);
    low_bytes = IoUtil::readU4(file);
}


// CONSTANT_Utf8_info
void CONSTANT_Utf8_info::readFrom(std::istream& file) {
    // 读取长度
    length = IoUtil::readU2(file);
    delete[] bytes;
    // 读取字符串数据
    if (length > 0) {
        bytes = new u1[length];
        for (u2 i = 0; i < length; i++) {
            bytes[i] = IoUtil::readU1(file);
        }
    } else {
        bytes = nullptr;
    }
}

读取代码

这里注意几点

  • long和duble占用两个索引
  • 常量池的个数是constant_pool_count-1
  • 我这里设计的ConstPool会用一个空的展位下标为0的
cpp 复制代码
// 读取常量池
void ClassFileReader::readConstantPool(std::istream& file, ClassFile* classFile) {
    classFile->constant_pool_count = IoUtil::readU2(file);

    // 创建新的常量池对象
    classFile->constant_pool = new ConstPool();

    // 读取每个常量池项
    for (u2 i = 1; i < classFile->constant_pool_count; i++) {
        u1 tag = IoUtil::readU1(file);

        // 使用工厂创建对应的常量池对象
        auto constant = std::unique_ptr<constant_pool_info>(ConstantPoolFactory::createConstant(tag));
        if (!constant) {
            throw std::runtime_error("Invalid constant pool tag: " + std::to_string(tag));
        }

        // 根据类型填充具体数据
        constant->readFrom(file);

        // 添加到常量池
        classFile->constant_pool->addConstant(std::move(constant));

        // Long和Double类型占用两个位置,需要跳过下一个位置
        if (ConstantPoolFactory::takesTwoSlots(tag)) {
            i++; // 跳过下一个位置,常量池会自动处理
        }
    }
    classFile->constant_pool->nameMapping();
}

运行代码展示

示例代码 本期略,发现还没实现完善的toString

结束以及参考

本文重点在于分享常量池的数据结构定义,实现代码较为简单不是本文重点。这里充分利用面向对象的设计思路,把解析分担给各个实现类。

参考和链接:

Chapter 4. The class File Format

JVM字节码attribute_info

JVM StackMapTable 属性详解

JVM字节码数据结构总览和读取

相关推荐
nono牛1 小时前
C++ 语言全面教程 (基础入门)
java·jvm·c++
Zzzzzxl_1 小时前
深入理解Java JVM中的垃圾回收器
java·jvm·编程·性能调优·垃圾回收
〝七夜56911 小时前
JVM内存结构
java·开发语言·jvm
一只小透明啊啊啊啊16 小时前
垃圾回收算法有哪些
java·jvm
平原人16 小时前
JVM字节码数据结构总览和读取
jvm·字节码
程序员梁白开18 小时前
从源码到实战:线程池处理任务的完整流程解析
java·jvm·spring·java-ee
safestar201220 小时前
Elasticsearch ILM实战:从数据热恋到冷静归档的自动化管理
java·开发语言·jvm·elasticsearch·es
北郭guo21 小时前
垃圾回收底层原理【深入了解】
java·jvm·算法
7***47711 天前
【SQL】掌握SQL查询技巧:数据分组与排序
java·jvm·sql