"String str = new String("abc") 创建了几个对象?"这个经典面试题看似简单,却涵盖了Java字符串处理的核心机制。作为从业十余年的Java开发者,我见过太多候选人在这里栽跟头。今天我们就彻底拆解这个问题,不仅告诉你答案,更要让你理解背后的设计哲学。
字符串对象创建涉及三个关键区域:字符串常量池、堆内存和方法区。当面试官抛出这个问题时,他真正想考察的是:
当JVM首次遇到"abc"字面量时:
关键点:常量池位于方法区(JDK7前)或堆内存(JDK7+),但逻辑行为一致。这个创建动作发生在类加载阶段,而非代码执行时。
当执行new String("abc")时:
注意:这里容易误解的是new String()会创建新的char数组。实际上从JDK6开始,String内部会复用原char[](除非显式调用copy构造函数)。
用实际内存地址说明更直观:
code复制常量池: 0x1000 - "abc" (字面量首次出现时创建)
堆内存: 0x2000 - String对象 (new时创建)
此时:
验证代码:
java复制String s1 = "abc";
String s2 = new String("abc");
System.out.println(System.identityHashCode(s1)); // 输出常量池对象hash
System.out.println(System.identityHashCode(s2)); // 输出堆对象hash
在以下场景可能只创建1个对象:
java复制String a = "abc";
String b = "abc"; // 复用常量池对象
java复制String c = "a" + "b" + "c"; // 编译优化为"abc"
但new String()永远会在堆上创建新实例,这是语言规范保证的行为。
资深面试官可能延伸提问:
"abc".intern()的作用是什么?
String s = new String("abc") + new String("def")创建几个对象?
JDK6 vs JDK7+的字符串常量池区别?
实际开发中要注意:
避免循环内new String:
java复制// 错误示范
for(int i=0; i<10000; i++) {
String s = new String("constant");
}
这会导致大量重复堆对象创建
优先使用字面量赋值:
java复制// 正确做法
String s = "constant";
大文本处理应明确指定字符集:
java复制new String(byteArr, "UTF-8"); // 显式声明编码
从JVM角度看:
字符串常量池本质是HashTable:
String对象结构(以JDK17为例):
cpp复制class String {
private final byte[] value;
private final byte coder; // 0-Latin1, 1-UTF16
private int hash;
}
现代JDK使用紧凑字符串优化,Latin1字符用单字节存储
对象创建字节码分析:
java复制ldc "abc" // 加载常量池引用
invokespecial String.<init> // 调用构造方法
重要变更时间线:
通过以下代码验证理解:
java复制public class StringCreationLab {
public static void main(String[] args) {
// 场景1:纯字面量
String s1 = "java";
String s2 = "java";
System.out.println(s1 == s2); // true
// 场景2:显式new
String s3 = new String("java");
System.out.println(s1 == s3); // false
// 场景3:intern处理
String s4 = s3.intern();
System.out.println(s1 == s4); // true
// 场景4:运行时拼接
String s5 = "ja" + "va";
System.out.println(s1 == s5); // true(编译期优化)
}
}
根据项目特点选择策略:
内存敏感场景的特别处理:
java复制// 减少大字符串内存占用
String largeStr = "...";
largeStr = new String(largeStr.toCharArray()); // 切断与原char[]的关联
这个问题之所以成为经典,是因为它串联了JVM内存模型、编译器优化、字符串不可变性等多方面知识。真正理解它,你就掌握了Java字符串处理的精髓。