java字符串不可变,指对象内部final byte[] value等状态初始化后无法修改;==比较内存地址,equals比较字符内容;常量池在jdk7+位于堆中;new string("abc")至少创建1个堆对象,若常量池无该字面量则共2个对象。

Java 字符串是面试高频考点,想拿满分,关键不是背结论,而是讲清“为什么”——比如 String 为什么不可变、== 和 .equals() 到底比什么、常量池在哪儿、new String("abc") 创建了几个对象。下面直击核心,不绕弯。
String 不可变,到底“不可变”在哪?
不是指引用不能变,而是指对象内部的字符数组(JDK 9+ 是 byte[])、哈希值、长度等状态一旦初始化就无法修改。底层 final 修饰数组引用 + 构造后不提供修改方法 + 所有“修改”操作(如 substring、toUpperCase)都返回新对象。
- 好处:线程安全、可作 HashMap 键、节省内存(字符串池复用)、提升安全性(避免被篡改)
- 注意:不可变 ≠ 对象地址不变 —— 引用可以重新赋值,但原对象内容永远固定
String == 和 .equals() 的本质区别
== 比的是对象内存地址;.equals() 在 String 中被重写,比的是字符序列是否完全相同(逐个 char 或 byte 比较)。
- 字面量直接赋值(
String s = "abc")→ 走字符串常量池,相同内容指向同一对象 →==可能为 true -
new String("abc")→ 一定在堆中新建对象 → 即使内容相同,==也为 false - 务必优先用
.equals()判断内容相等;==只用于确认是否为同一对象(如检查 intern 结果或单例场景)
字符串常量池的位置和触发时机
JDK 7+ 后,字符串常量池从永久代(PermGen)移到堆内存中,和普通对象一样受 GC 管理。
- 编译期确定的字面量(如
"hello")在类加载时进入常量池 -
String.intern():如果池中已有相同内容字符串,返回池中引用;否则将当前字符串加入池并返回其引用 - 注意:
new String("abc").intern()在 JDK 7+ 中返回的是常量池中已有的对象(若存在),不是新对象
常见陷阱题怎么答才显深度
别只说“对”或“错”,要带上下文和版本差异:
- “String s = new String("ab"); 创建了几个对象?” → 答:至少 1 个(堆中 new 出的对象);若常量池中原来没有 "ab",则再加 1 个(字面量进池),共 2 个。JDK 7+ 后常量池在堆里,“2 个对象都在堆中”更准确
-
“StringBuilder 和 StringBuffer 的区别?” → 不止说“线程安全”,要点明:StringBuffer 方法加了
synchronized,StringBuilder 没有;多数场景用 StringBuilder,仅多线程共享且无外部同步时才选 StringBuffer -
“String 拼接哪种方式效率高?” → 编译期能确定的(如
"a" + "b")直接优化成字面量;运行期拼接推荐 StringBuilder(单线程)或 StringBuffer(多线程);避免在循环里用+=(隐式创建多个 StringBuilder)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











