Java中String的不可变性是类加载机制可靠运行的关键设计:它确保类名等核心标识绝对稳定,防止恶意篡改导致类型系统崩溃,支撑字符串常量池共享、符号引用解析确定性及类加载线程安全。

Java 中 String 的不可变性与类加载机制紧密耦合,不是巧合,而是关键设计依赖——类加载器靠字符串标识类,而这些字符串一旦可变,整个类型系统就可能崩溃。
类名作为核心标识必须绝对稳定
类加载过程从“全限定类名”(如 java.lang.String)开始。JVM 用这个字符串去定位 .class 文件、查常量池、验证签名。如果 String 可变,一段恶意或意外代码就能在类加载中途改写类名:
- 原本要加载 java.util.ArrayList,结果被中间某处调用
className.replace("ArrayList", "EvilHook")改成 java.util.EvilHook - 类加载器会照单全收,加载并执行非预期类,绕过安全校验
字符串常量池支撑类加载的复用与一致性
类加载过程中大量使用字符串字面量(如包名、方法名、字段名),它们都存于字符串常量池中。String 不可变保障了:
- 多个类加载器(如 Bootstrap、Extension、AppClassLoader)可安全共享同一份类名字符串,无需拷贝或加锁
- 同一个类名(如 java.io.File)在不同上下文中始终指向唯一、不变的实例,避免因内容被篡改导致类定义错乱
- 符号引用解析阶段(如
ldc指令加载类名常量)结果确定且可缓存
final 类 + 私有 final 字段构成底层防线
仅靠“逻辑上不改”不够,JVM 要求语义级保障:
立即学习“Java免费学习笔记(深入)”;
-
public final class String阻止继承——子类无法重写getClass()或注入修改逻辑 -
private final byte[] value(JDK 9+)或private final char[] value(JDK 8)封住内部数据入口 - 所有构造方法做防御性拷贝(如
Arrays.copyOf),防止外部数组引用泄露后被篡改
不可变性让类加载具备天然线程安全性
多线程并发触发类加载(如首次访问某个类)时,无需同步字符串参数:
- 传入的类名字符串(如
"com.example.Service")本身不会被任何线程修改 - 类加载器可放心缓存已解析的类名 → Class 映射,不必担心键值失效或哈希冲突突变
- 避免因字符串状态变化引发的 ClassCastException 或 NoClassDefFoundError 等运行时异常


















