String 为什么是不可变的?
String 为什么是不可变的?
String 类中使用 final 关键字修饰字符数组来保存字符串,所以String 对象是不可变的。
1 | public final class String implements java.io.Serializable, Comparable<String>, CharSequence { |
🐛 修正:我们知道被
final关键字修饰的类不能被继承,修饰的方法不能被重写,修饰的变量是基本数据类型则值不能改变,修饰的变量是引用类型则不能再指向其他对象。因此,final关键字修饰的数组保存字符串并不是String不可变的根本原因,因为这个数组保存的字符串是可变的(final修饰引用类型变量的情况)。
String真正不可变有下面几点原因:1. 保存字符串的数组被
final修饰且为私有的,并且String类没有提供/暴露修改这个字符串的方法。
2.String类被final修饰导致其不能被继承,进而避免了子类破坏String不可变。相关阅读:如何理解 String 类型值的不可变? - 知乎提问open in new window
在 Java 9 之后,
String、StringBuilder与StringBuffer的实现改用byte数组存储字符串。
1 | public final class String implements java.io.Serializable,Comparable<String>, CharSequence { |
Java 9 为何要将
String的底层实现由char[]改成了byte[]?新版的 String 其实支持两个编码方案:Latin-1 和 UTF-16。如果字符串中包含的汉字没有超过 Latin-1 可表示范围内的字符,那就会使用 Latin-1 作为编码方案。Latin-1 编码方案下,
byte占一个字节(8 位),char占用 2 个字节(16),byte相较char节省一半的内存空间。
String不可变的意义
String 类在 Java 中是一个非常重要的类,它表示字符序列,并且设计为不可变的(immutable)。String 类底层使用 final char[] value 数组来存储字符数据,这意味着一旦创建了一个 String 对象,它的内容就不能再被更改。不可变性带来了多个好处:
- 线程安全:
- 不可变性保证了
String对象在多线程环境中是安全的,因为它的内容不会改变。这意味着多个线程可以共享一个String对象,而不用担心数据一致性问题。
- 节省内存:
- Java 运行时会在字符串常量池中存储字符串字面量,如果存在相同的字符串字面量,就会共享相同的内存空间。这种共享减少了重复字符串的存储,节省了内存资源。例如,
String s1 = "abc"; String s2 = "abc";在这种情况下,s1和s2引用的是同一个对象。
- 简化编程模型:
- 不可变性简化了编程模型,因为一旦创建了
String对象,就不需要担心后续的操作会改变它的内容。这有助于减少程序中的错误。
- 哈希码稳定性:
String类重写了hashCode方法,使其返回值依赖于字符串的内容。由于String是不可变的,其哈希码在对象创建时计算一次即可,之后不会改变。这对于HashMap或其他依赖哈希码的数据结构非常重要,因为哈希码的变化会导致这些数据结构无法正常工作。
- 方便作为键使用:
- 由于
String的不可变性,它可以安全地作为HashMap或其他集合框架中的键使用。当String作为键时,其内容不会改变,因此总是可以正确地找到对应的值。
- 简化内部优化:
- JVM 能够对不可变的
String做更多的优化,因为它们的内容永远不会改变。例如,JIT 编译器可以更自由地缓存结果,提高性能。
- 简化序列化过程:
- 由于
String对象是不可变的,它们在序列化和反序列化过程中不会出现问题,因为对象的状态不会发生变化。





