java中string无深浅拷贝之分,因不可变性与常量池机制:赋值为引用共享(==为true),但安全;new、substring等创建新对象(==为false);字面量自动入池复用。

Java 中 String 的引用与拷贝,核心在于它的不可变性和字符串常量池机制。它不像普通对象那样存在“深浅拷贝”的典型区分,而是通过引用关系、对象创建时机和内存布局共同决定行为。
String 是不可变对象,所有“修改”都是新建
String 内部用 private final char[](或 byte[])存储内容,且没有提供任何修改数组的方法。所以:
- 任何看似修改的操作(如
substring、concat、replace、+)都会返回一个全新的 String 对象; - 原对象内容始终不变,也不会被影响;
- 这使得 String 天然线程安全,也消除了对传统“深拷贝”的需求。
直接赋值是引用复制,不是内容拷贝
写 String s1 = "abc"; String s2 = s1; 时:
- s1 和 s2 指向同一个对象(如果字面量已在字符串常量池中存在);
- 用
==比较结果为true; - 但这不是“危险的共享”,因为 String 不可变 —— 即使两个变量共用一个对象,谁都改不了它。
显式创建新对象才算真正“拷贝”
以下方式会生成堆中独立的新 String 实例(即使内容相同),== 比较为 false:
-
new String("abc"):强制在堆中新建,绕过常量池; -
"abc".substring(0)或"abc".substring(0, 3):返回新对象(JDK 7+ 后 substring 不再共享底层数组); -
new String("abc".toCharArray()):先转数组再建新串; -
"abc".concat(""):拼空串,返回新对象。
字符串常量池让相同字面量自动复用
编译期确定的字符串字面量(如 "hello"、"ab")会被放入字符串常量池:
-
String a = "ab"; String b = "a" + "b";→ 编译器优化为"ab",a 和 b 指向同一池中对象; -
String c = new String("ab");→ 在堆中新建,与池中对象不同(c == a为false); - 调用
c.intern()可将其加入常量池或返回已有引用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











