public static final int CONST = 100; int y = CONST;
0: bipush 100
像这里,是直接使用100,还是需要用到常量池中100?
就是常量池中的100还有必要存在吗?已经写入了字节码指令中了
非常精准的问题!我们来深入拆一下字节码细节,看看这个 100 到底是不是还“依赖常量池”:
🔍 场景还原
public class Test {
public static final int CONST = 100;
public static void main(String[] args) {
int y = CONST;
System.out.println(y);
}
}
javac 编译后:
javap -c -v Test
部分输出(简化):
Constant pool:
#1 = Methodref #6.#15 // java/lang/Object."<init>":()V
#2 = Fieldref #16.#17 // java/lang/System.out:Ljava/io/PrintStream;
#3 = Methodref #18.#19 // java/io/PrintStream.println:(I)V
#4 = Integer 100
...
Code:
0: bipush 100
2: istore_1
3: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
6: iload_1
7: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
🔑 分析
-
bipush 100bipush是一个 JVM 指令,表示“直接将一个字节大小的常量压入操作数栈”。- 这里的
100是直接写在字节码指令后的立即数(immediate operand),完全不依赖常量池。
-
常量池的
#4 = Integer 100- 这是
.class文件常量池中的一个CONSTANT_Integer_info表项。 - 它保留了类中用到的字面量
100,即使生成了bipush 100指令,这个表项依然存在于常量池。 - 但对于运行时执行
bipush 100,JVM 根本不会去查常量池的 #4,它直接取字节码里的立即数。
- 这是
-
为什么常量池还保留这个表项?
.class文件的规范要求:源码中出现的字面量常量必须记录在常量池表中(即 Class 文件是“自描述”的)。- 编译器生成
bipush时已经优化为直接数值,运行时不访问这个常量池表项。 - 所以这个
#4是“静态元信息”,主要用于类文件完整性和调试工具,不是执行时必需。
✅结论
-
执行时:
bipush 100指令直接把字节码里的立即数100压栈,不查常量池。
-
常量池中的
Integer 100:- 只是
.class文件规范要求的字面量记录,对运行时这条指令没用。 - 保留它是为了让
.class文件完整、可反编译、可被其他工具读取。
- 只是
📌一句话:
对于可以直接用
bipush/sipush/ldc表达的常量,JVM 字节码直接携带立即数,执行时不依赖常量池表项;常量池里的数值更多是类文件元信息。
3323

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



