Java 基础 整理
String 为什么不可变?先别只回答 final
不可变是一组设计约束,final 只是其中一部分。
先回答:String 用了 final,所以就是不可变的吗?
不能只凭 final 判断不可变。final 引用不能重新指向另一个对象,但被引用对象的内容仍可能改变。String 的不可变性还依赖私有内部存储、不暴露可变内容、不提供修改自身内容的方法,以及类本身不允许被继承等设计。
final 约束的是哪一层
final List<String> names = new ArrayList<>();
names.add("Java"); // 可以修改列表内容
// names = new ArrayList<>(); // 不能重新赋值
这个例子说明,final 引用不等于引用的对象不可变。谈不可变时,应同时考虑状态封装、构造过程和对外暴露的接口。
String 的内部实现会随 JDK 变化
JDK 8 的 String 主要使用 char[] 保存内容。JDK 9 引入 Compact Strings,在可用时以 byte[] 配合编码标记存储。讨论源码时需要先说明 JDK 版本,不要把某个版本的字段布局当作所有版本的固定事实。
substring、replace、拼接等操作不会修改原 String 的字符内容,而是返回一个结果;结果是否创建新对象,不能仅凭方法名一概判断。
不可变带来的好处与边界
- 对象可以在多处共享,而不必担心某个调用方通过常规接口改掉它的内容。
- 适合作为映射键,内容不会在入表后被修改,从而影响内容哈希与相等性判断。
- String 对象内容不可变,不意味着装着它的变量或容器自动具备线程安全性。
- 大量循环拼接通常应考虑局部 StringBuilder,但也要先看编译方式、实际规模和性能测量。
延伸阅读
以上为个人整理。涉及版本实现和线上使用时,请结合对应文档与实际测试判断。