jdk 8及以前string底层用private final char[] value存储,每个char占2字节(utf-16),数组引用不可重赋值、私有封装且无修改api,共同保障不可变性。

Java 中 String 的底层存储在 JDK 8 及以前版本确实是通过 char[] 数组 实现的,这是理解其不可变性和内存行为的关键起点。
char[] 是怎么存字符的
源码中关键字段是:
private final char value[];
这个数组每个元素占 2 字节(Java 使用 UTF-16 编码),无论存英文、数字还是中文,都按一个 char 单元处理。比如:
-
"abc"→ 底层是{'a', 'b', 'c'},长度为 3,占用 6 字节 -
"你好"→ 底层是{'你', '好'},长度也为 2,同样占 4 字节(基本 BMP 字符)
注意:遇到增补字符(如某些 emoji),可能用两个 char(代理对)表示一个 Unicode 码点,但数组长度仍按 char 计,不是按“字符个数”。
用于 inference.sh 的 JavaScript/TypeScript SDK,可运行 AI 应用、构建代理、集成 150+ 模型。包名:@inferencesh/sdk(npm install),完整 TypeScript 支持。
为什么用 final char[] 就能保证不可变
不可变性不是靠“禁止修改字符串内容”的魔法,而是靠三重约束:
- private:外部类无法直接访问 value 数组
- final:value 引用本身不可重新赋值(不能指向另一个数组)
- 无公开修改方法:String 类不提供 setCharAt、append 等会改动 value 的 API
即使你通过反射强行改 value 内容,也属于破坏封装的非标准行为,JVM 不保证结果正确,且 hash 值等缓存会失效。
构造时如何把数据放进 char[]
以 new String("hello") 为例(JDK 8):
- 字面量
"hello"先在常量池生成一个 String 对象,其value是共享的 char[] -
new String(...)构造器内部会调用Arrays.copyOf(value, value.length),新建一个独立的 char[] 并拷贝内容 - 所以两个字符串内容相同,但
==为 false —— 它们的value数组地址不同
这种拷贝机制确保了新对象与原对象彻底隔离,进一步加固不可变语义。
这种设计带来的实际影响
使用 char[] 存储虽简单可靠,但也带来明显代价:
- 纯 ASCII 字符串(如 HTTP header、日志 ID)浪费 50% 内存:每个字母本只需 1 字节,却占 2 字节
- 字符串越长,堆内存压力越明显,尤其在高并发文本处理场景
- 这也是 JDK 9 引入 Compact Strings(改用 byte[] + coder)的根本原因
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










