Java中只有满足编译期常量表达式的字符串字面量、基本类型静态final常量、类/方法/字段符号信息等才进入运行时常量池,用于内存复用、高效解析和动态链接。
Java中类的常量(如字符串字面量、基本类型编译期常量)被放入运行时常量池(Runtime Constant Pool),本质是为了实现内存复用、提升性能,并支持JVM对符号引用的解析和动态链接。这不是“所有常量都进常量池”,而是有明确规则的——只有满足特定条件的常量才会在类加载阶段被存入常量池。
不是所有带final的变量都进常量池,关键看是否满足编译期可确定的常量表达式
:
"hello")一定进常量池;用new String("hello")创建的则不会(对象在堆中)public static final int MAX = 100; 这类基本类型+编译期常量值的静态字段,其值会被直接“内联”进调用处,同时该字面量100也会存入常量池public static final String NAME = "Tom"; 同样进常量池;但public static final String NAME = new String("Tom"); 不会(因为运行期才创建)常量池是每个类或接口独立拥有的,存储在方法区(JDK 7+ 逻辑上在堆中,JDK 8+ 元空间)。不同类里相同的字符串字面量,在各自常量池中是独立条目;但通过String.intern()可手动将其映射到全局字符串表(String Table),实现跨类共享。
例如:
class A { static final String s = "abc"; }
class B { static final String t = "abc"; }String实例(除非显式调用intern())。
常量池数据在类加载的“准备”阶段之后、“解析”阶段之中完成初始化:
0、null)s = "abc")发生在“初始化”阶段,但"abc"本身早已在解析阶段进了常量池常量池是JVM实现高效链接与运行时优化的基础设施:
基本上就这些。常量池不是黑盒缓存,而是JVM链接模型的核心枢纽——它让编译后的字节码保持紧凑,又为运行时的灵活解析留出空间。理解它,才能真正看懂类加载、字符串比较、反射调用背后的逻辑。