Java字节码其实就是 .class 文件.
我们写出的Java源代码经过编译后就会变成 class文件。
编译过程
源代码是程序员写的。JVM识别不了,因此需要编译器主要对源码代码做编译处理,大致如下:
词法分析器 => 语法分析器 => 语法树/抽象语法树 => 语义分析器 => 注解抽象语法树 => 字节码生成器 => class文件
这个过程涉及编译原理,就不说了。
执行以下命令即可对类进行编译
javac XXX.java
Class文件
编译后一个类就用一个 .class 文件表示。官网描述其结构如下
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count; // 常量池中常量个数
cp_info constant_pool[constant_pool_count-1]; // 常量池
u2 access_flags; // 类的访问控制标识 public、protect 等
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]; // 属性集合
}
说明:
- magic 表示这是 class 文件,值是
0xCAFEBABE -
minor_version, major_version 代表 java 不同的版本
-
constant_pool_count常量池的大小(因为有一个预留,因此实际值=该值-1) -
cp_info常量池 -
这里
u4代表无符号的4字节.u2代表2个字节 -
每一项都是类的具体信息构成
常量池
对于常量池,官网说法是:
Java虚拟机指令不依赖于类、接口、类实例或数组的运行时布局。相反,指令引用constant_pool表中的符号信息。
常量池中,每一项的结构如下:
cp_info {
u1 tag;
u1 info[];
}
先是一个字节表示是哪种常量(tag),接下来是每一项的具体信息:
| Constant Kind |
Tag |
结构 |
含义 |
| CONSTANT_Utf8 |
1 |
CONSTANT_Utf8_info { u1 tag; u2 length; u1 bytes[length]; } |
常量字符串值 |
| CONSTANT_Integer |
3 |
CONSTANT_Integer_info { u1 tag; u4 bytes; } |
整型常量值 |
| CONSTANT_Float |
4 |
CONSTANT_Float_info { u1 tag; u4 bytes; } |
浮点型常量值 |
| CONSTANT_Long |
5 |
CONSTANT_Long_info { u1 tag; |
本文介绍了Java字节码的概念,详细阐述了Java源代码如何通过编译过程转化为.class文件,包括Class文件结构、常量池、运行时数据区和字节码指令的解析。通过示例展示了字节码指令如何在JVM中执行,并提到了JDK提供的反编译工具javap以及一些辅助的字节码阅读工具。
最低0.47元/天 解锁文章
142

被折叠的 条评论
为什么被折叠?



