面试知识库
基础

String不可变性#

一句话答案#

String 用 final 类 + private final char[] 实现不可变,好处:线程安全、哈希值缓存、字符串池复用、安全性。

核心要点

实现: final类 + private final char[] + 不提供修改方法

好处: 1.线程安全 2.hashCode缓存(HashMap的key) 3.字符串常量池复用 4.安全性(不可被篡改)

面试回答(2分钟版)

String 的不可变性通过三道防线实现:第一,String 类本身是 final 的,不能被继承,防止子类破坏不可变性;第二,底层存储字符的 char 数组声明为 private final,final 保证引用不能指向新数组,private 防止外部直接访问;第三,String 类不提供任何修改内部数组的方法,所有看起来像修改的操作如 concat、replace 都是返回新的 String 对象。不可变性带来四个重要好处:线程天然安全,多线程共享不需要同步;hashCode 可以在首次计算后缓存起来,作为 HashMap 的 key 时效率极高;支持字符串常量池机制,相同内容的字符串可以复用同一个对象节省内存;用于类加载器路径、网络连接参数等安全敏感场景时不怕被篡改。JDK 7 之后字符串常量池从方法区移到了堆中。理论上 JDK 8 可以通过反射修改 String 内部数组,但 JDK 9 引入模块系统后做了更严格的访问限制。

追问与易错

追问方向:

  • “String 不可变是怎么实现的?”→ 三道防线:String 类声明为 final 不可继承、底层 char[] 为 private final 引用不可变且外部不可访问、不提供任何修改内部数组的方法
  • “可以通过反射修改 String 吗?”→ JDK8 可以通过反射 setAccessible(true) 修改 value 数组内容;JDK9+ 引入模块系统(JPMS)做了更严格的访问限制,默认不可反射修改
  • “字符串常量池在哪里?”→ JDK7 之前在方法区(永久代),JDK7 开始移到堆中,便于 GC 回收不再使用的常量字符串,避免永久代 OOM

易错点:

  • ❌ “final char[] 就保证了不可变”——final 只保证引用不变,还需要不暴露修改方法
  • ❌ 混淆 String.intern() 的行为——JDK7+ 不再复制字符串到常量池,而是存引用