全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-09 6 分钟 ✍️ juanwangdev

字符串不可变性

String对象一旦创建,内容不能被修改。

不可变性概念

什么是不可变

字符串对象创建后,其内容不可更改,任何修改操作都会产生新对象。

Java
String str = "Hello";
str = str + " World";  // 看似修改,实际创建新对象

// 原字符串"Hello"仍在内存中
// 新字符串"Hello World"是新创建的对象

不可变性的本质

String类内部数组是final的,不可修改。

Java
// String类源码(简化)
public final class String {
    private final char[] value;  // final修饰,不可变
    
    // 没有提供修改value数组的方法
}

不可变性验证

看似修改实则新建

Java
String s1 = "Hello";
String s2 = s1.concat(" World");  // 拼接操作

System.out.println(s1);  // "Hello"(原字符串未变)
System.out.println(s2);  // "Hello World"(新字符串)

// s1和s2是不同的对象
System.out.println(s1 == s2);  // false

所有操作返回新对象

Java
String str = "Hello";

// 每个操作都返回新字符串
String upper = str.toUpperCase();   // "HELLO"(新对象)
String sub = str.substring(1);      // "ello"(新对象)
String rep = str.replace('H', 'J'); // "Jello"(新对象)

// 原字符串不变
System.out.println(str);  // "Hello"

不可变性的好处

安全性

字符串不可被篡改,适合存储敏感信息。

Java
// 作为参数传递,不会被修改
public void process(String param) {
    // param内容安全,不会被意外修改
}

// 多线程共享安全
String shared = "配置信息";  // 多线程访问无需加锁

字符串常量池优化

不可变才能安全共享,实现常量池。

Java
String s1 = "Java";
String s2 = "Java";
// s1和s2共享同一对象,节省内存

// 如果可变,s1修改会影响s2

HashMap键的稳定性

字符串作为HashMap键,hashCode稳定。

Java
Map<String, Object> map = new HashMap<>();
map.put("key", value);

// 字符串不可变,hashCode不变
// 如果可变,key内容改变后hashCode改变,无法找到value

安全传递

字符串传递给其他方法或类时不会被修改。

Java
String url = "http://example.com";
Connection conn = connect(url);
// url不会被connect方法修改

不可变性的代价

拼接产生大量对象

Java
// 低效:每次拼接创建新对象
String result = "";
for (int i = 0; i < 1000; i++) {
    result = result + i;  // 创建1000个临时对象
}

// 高效:使用StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append(i);  // 不创建新对象
}
String result = sb.toString();

内存占用

大量字符串操作会产生临时对象,增加GC压力。

Java
// 临时对象示例
String a = "A";
String b = "B";
String c = a + b;  // 创建临时StringBuilder,再创建String
// 产生额外对象

不可变性的实现机制

final类和final字段

Java
// String是final类,不能继承
public final class String {
    
    // value数组是final,不可替换
    private final char[] value;
    
    // 没有setter方法
    // 所有修改方法返回新对象
}

私有字段无修改方法

Java
// value数组私有,外部无法访问
// 没有提供修改value内容的方法
// concat、substring等方法内部创建新数组

不可变性相关面试题

为什么String设计为不可变?

  1. 安全性:防止意外修改,适合存储敏感信息
  2. 常量池:支持字符串常量池共享
  3. 线程安全:多线程访问无需同步
  4. hashCode稳定:适合作为HashMap键

String能否真正修改?

技术上可以通过反射修改,但不推荐。

Java
// 反射修改(不推荐,破坏安全性)
String str = "Hello";
Field field = String.class.getDeclaredField("value");
field.setAccessible(true);
char[] chars = (char[]) field.get(str);
chars[0] = 'J';  // 修改底层数组

// 实际变为"Jello",但这是危险操作

常见误解

误解1:str = str + "x"是修改

Java
String str = "Hello";
str = str + "World";

// 不是修改原对象
// 是创建新对象,str指向新对象
// 原对象"Hello"仍在内存中(可能被GC回收)

误解2:substring修改原字符串

Java
String str = "Hello World";
String sub = str.substring(0, 5);

System.out.println(str);  // "Hello World"(未变)
System.out.println(sub);  // "Hello"(新对象)

要点总结

  • String不可变:创建后内容不能修改
  • 所有修改操作返回新对象
  • 底层final char[]保证不可变
  • String类是final类,不能继承
  • 好处:安全、常量池共享、线程安全、hashCode稳定
  • 代价:频繁拼接产生大量临时对象
  • 拼接大量字符串用StringBuilder
  • 作为HashMap键稳定可靠
  • 多线程访问无需同步
  • 反射可修改但不推荐

📝 发现内容有误?点击此处直接编辑

← 上一篇 StringBuilder与StringBuffer
下一篇 → 字符串与字符数组转换
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库