字节码与操作数栈
# 字节码概念
# Classfile
markdownCopy code
Classfile /Users/wenkailiu/work/workspaces/jvm-demo/target/classes/com/olight/cloud/jvmModel/ByteCodeInterView.class
1
2
2
- Classfile: 显示类文件的路径。
# Class Metadata
markdownCopy code
Last modified Apr 17, 2024; size 1768 bytes
SHA-256 checksum 7d20ce44559d2f0a5ef07187de3d45aaa9b69274a23eb5934d58c05e3b68eb49
Compiled from "ByteCodeInterView.java"
1
2
3
4
2
3
4
- Last modified: 类文件最后修改日期。
- size: 文件大小。
- SHA-256 checksum: 文件的SHA-256校验和,用于验证文件完整性。
- Compiled from: 源文件名称。
# Class Declaration
markdownCopy code
public class com.olight.cloud.jvmModel.ByteCodeInterView
minor version: 0
major version: 52
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #8 // com/olight/cloud/jvmModel/ByteCodeInterView
super_class: #9 // java/lang/Object
interfaces: 0, fields: 0, methods: 4, attributes: 1
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
- minor version 和 major version: 分别表示类文件的次要和主要版本号。
- flags: 类的访问标志,例如
ACC_PUBLIC
表示公共类,ACC_SUPER
用于允许某些特殊的方法调用指令。 - this_class: 当前类的常量池索引。
- super_class: 父类的常量池索引。
- interfaces, fields, methods, attributes: 接口、字段、方法和属性的数量。
# Constant Pool
markdownCopy code
Constant pool:
#1 = Methodref #9.#49 // java/lang/Object."<init>":()V
...
1
2
3
4
2
3
4
- Constant pool: 常量池条目,每个条目都有一个索引。常量池存储了各种常量信息,包括类、接口、字段和方法的符号引用,以及字面量(如字符串常量)。
# Methods
markdownCopy code
public com.olight.cloud.jvmModel.ByteCodeInterView();
...
public void typeTest();
...
public int mathTest();
...
public int inc();
...
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
每个方法都有详细的信息,包括:
descriptor: 方法的描述符,说明方法的参数和返回类型。
flags: 方法的访问标志,如
ACC_PUBLIC
。Code
: 方法的字节码指令和其他信息。
- stack: 最大堆栈深度。
- locals: 局部变量表大小。
- args_size: 参数数量。
LineNumberTable: 源文件中行号到字节码指令的映射。
LocalVariableTable: 局部变量的描述,包括其生命周期内的作用域。
StackMapTable: 用于验证和优化字节码执行的类型信息。
# Attributes
markdownCopy code
RuntimeVisibleAnnotations:
...
1
2
3
2
3
- Attributes: 类、字段或方法级别的附加信息,如注解、泛型签名等。
# SourceFile
markdownCopy code
SourceFile: "ByteCodeInterView.java"
1
2
2
- SourceFile: 指明这个类文件是从哪个源文件编译来的。
# TypeTest解释
这个 typeTest
方法展示了 Java 中的自动装箱行为和它对 ==
操作符的影响。以下是 javap -verbose
命令输出中每个部分的详细解释:
# 方法声明和描述符
markdownCopy code
public void typeTest();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
1
2
3
4
2
3
4
- descriptor: ()V - 这表示方法没有参数并且返回类型为
void
。 - flags: (0x0001) ACC_PUBLIC - 表示该方法是公开的。
# 字节码指令
这部分列出了该方法的所有 JVM 字节码指令:
- bipush: 将单字节的常量值(即5至10)推送至栈顶。
- invokestatic: 调用一个静态方法,这里用于
Integer.valueOf
,实现自动装箱。 - astore: 将栈顶引用类型值存入本地变量。
- getstatic: 获取指定类的静态字段,并将其值压入栈顶,这里用于获取
System.out
。 - if_acmpne: 比较栈顶两个引用类型数值,当不相等时跳转。
- iconst_1 和 iconst_0: 分别将int类型的1和0压入栈顶。
- goto: 无条件跳转。
- invokevirtual: 调用实例方法,这里用于
PrintStream.println
打印布尔值。
# 字节码逻辑详解
public void typeTest() {
Integer i1 = 10; // 自动装箱,调用 Integer.valueOf(10)
Integer i2 = 10; // 同上,Java缓存了-128到127之间的Integer对象,因此i1和i2指向相同的对象
System.out.println(i1 == i2); // true,因为i1和i2引用相同
Integer i3 = 128; // 自动装箱,调用 Integer.valueOf(128)
Integer i4 = 128; // 同上,但128不在缓存范围内,因此i3和i4是不同的对象
System.out.println(i3 == i4); // false,因为i3和i4引用不同
Boolean b1 = true; // 自动装箱,调用 Boolean.valueOf(true)
Boolean b2 = true; // 同上,Boolean.valueOf缓存了TRUE和FALSE实例,因此b1和b2是相同的对象
System.out.println(b1 == b2); // true
Double d1 = 1.0; // 自动装箱,调用 Double.valueOf(1.0)
Double d2 = 1.0; // 同上,但Double没有缓存除0以外的值,因此d1和d2是不同的对象
System.out.println(d1 == d2); // false
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 属性
- LineNumberTable: 显示源代码行号与字节码指令的对应关系。
- LocalVariableTable: 显示方法局部变量的范围、槽位索引、名称和描述符。
- StackMapTable: 提供了足够的信息来验证字节码的类型安全性,记录了特定程序点的局部变量和操作数栈的类型状态。
# 注解
- RuntimeVisibleAnnotations: 显示方法的运行时可见注解,这里用了 JUnit 的
@Test
注解。
这个方法主要用来演示不同类型的包装类在使用 ==
上次更新: 2024/04/19, 10:50:53