字符串创建需据场景选方式:字面量复用常量池,new String() 总建新堆对象;String.valueOf() 防空安全,toString() 要求非空;循环拼接用 StringBuilder;intern() 慎用,仅高重复==判断时考虑。

Java 中字符串创建不是“选一种方式就行”,而是得看你要的是对象复用、内存效率,还是明确需要新实例——String 的不可变性和字符串常量池机制,直接决定你写 new String("abc") 和 "abc" 时,JVM 干了完全不同的事。
字符串字面量 vs new String():本质区别在哪
字面量(如 "hello")会先查字符串常量池,存在就复用地址;new String("hello") 总是新建堆对象,哪怕内容一样,== 也返回 false。
常见错误现象:String a = "test"; String b = new String("test"); System.out.println(a == b); // 输出 false ——这不是 bug,是设计使然。
- 想复用、省内存、做快速相等判断(尤其配置名、状态码等固定值),优先用字面量
- 明确需要一个独立可变副本(比如后续要传给某个会修改内部
char[]的旧 API),才用new String(...) - JDK 7+ 后,常量池移到堆中,但语义没变:字面量仍进池,
new不进池
String.valueOf() 和 toString():什么时候该用哪个
String.valueOf(null) 返回字符串 "null",而 null.toString() 直接抛 NullPointerException。这是最实际的取舍点。
立即学习“Java免费学习笔记(深入)”;
使用场景:
- 处理可能为
null的任意对象(Integer、Boolean、自定义对象),无脑用String.valueOf(obj) - 确定对象非空且已重写
toString()(如LocalDateTime.now().toString()),可用toString(),语义更清晰 -
String.valueOf(char[])是安全复制字符数组的常用方式,避免外部修改影响字符串内容
StringBuilder / StringBuffer 创建字符串:别在循环里用 + 拼接
Java 编译器对字面量拼接(如 "a" + "b" + "c")会优化成单个常量;但对变量拼接(s1 + s2 + s3),每次 + 都隐式新建 StringBuilder,再 toString() ——循环里这么写,性能雪崩。
实操建议:
- 已知长度或拼接次数少(≤3 次),用
+无妨,代码简洁 - 循环内拼接、或拼接逻辑复杂,显式用
StringBuilder(单线程)或StringBuffer(多线程) - 初始化
StringBuilder时指定容量(如new StringBuilder(128)),避免多次扩容复制
StringBuilder sb = new StringBuilder(256);
for (String item : list) {
sb.append(item).append(",");
}
String result = sb.toString();
intern() 方法:谨慎使用的“强制入池”操作
intern() 会把字符串对象尝试加入常量池,并返回池中引用。但它不是免费午餐:
- JDK 7+ 后池在堆,但调用仍需同步,高并发下有竞争开销
- 池中对象生命周期与类加载器绑定,长期持有大量
intern()字符串可能导致内存泄漏 - 仅当你要做大量
==判断(比如解析 CSV 后按字段名分发),且字段名重复率极高时,才值得考虑
典型误用:new String("abc").intern() == "abc" 虽然成立,但毫无意义——不如直接用字面量。










