字符串字面量在String Constant Pool的存储机制及Line3返回false的原因
字符串常量池存储规则与拼接行为分析
一、字符串字面量在常量池的存储逻辑
当代码中出现字符串字面量(如"Hello World")时,JVM的处理流程是:
- 先检查字符串常量池,若池中已有内容完全一致的字符串对象,直接复用该对象的引用;
- 若池中不存在,则在常量池中创建该字符串对象,再返回其引用。
- 类加载阶段,类中定义的所有字符串字面量都会被预加载到常量池,这也是Line1输出
true的原因:Other.hello和Main中的hello指向常量池中的同一个对象。
二、为什么"Hello " + world的结果不在常量池?
字符串拼接的内存行为取决于操作数是否能在编译期确定结果:
- 纯字面量拼接(编译期可优化)
像"Hello " + "World"这种由多个字面量组成的拼接,编译器会直接将其优化为单个字面量"Hello World",所以它的引用直接指向常量池中的已有对象,对应Line2输出true。 - 包含变量的拼接(运行期生成)
当拼接操作中包含变量(比如world)时,JVM无法在编译期确定最终结果,会在堆内存中创建一个新的String对象来存储拼接后的内容,这个新对象不会自动进入字符串常量池。这就是Line3输出false的核心原因:hello指向常量池的对象,而"Hello " + world的结果是堆中的新对象,两者引用地址不同。
三、代码逐行解析
示例代码
class Other { static String hello = "Hello World"; } public class Main { public static void main(String[] args) { String hello = "Hello World", world = "World"; System.out.println(Other.hello == hello); // Line1 System.out.println(hello == ("Hello " + "World")); // Line2 System.out.println(hello == ("Hello " + world)); // Line3 System.out.println(hello == ("Hello " + world).intern()); // Line4 System.out.println(Integer.toHexString(hello.hashCode())); System.out.println(Integer.toHexString(("Hello " + "World").hashCode())); System.out.println(Integer.toHexString(("Hello " + world).hashCode())); System.out.println(Integer.toHexString(("Hello " + world).intern().hashCode())); } }
输出结果
true true false true 42628b2 42628b2 42628b2 42628b2
逐行说明
- Line1:两个变量都指向常量池中的同一个
"Hello World"对象,引用地址相同,输出true。 - Line2:编译期优化后,
"Hello " + "World"等价于"Hello World",指向常量池对象,输出true。 - Line3:
"Hello " + world在堆中生成新对象,和常量池对象引用不同,输出false。 - Line4:
intern()方法会检查常量池,发现已有"Hello World",返回常量池中的引用,和hello地址相同,输出true。 - hashCode输出:所有字符串的内容都是
"Hello World",而String的hashCode是基于内容计算的,所以结果完全一致,和对象所在内存区域无关。
内容的提问来源于stack exchange,提问作者Kushagra Shahi
相关产品推荐
相关产品推荐

