java 9起string默认启用compact strings机制,通过byte[]+coder字段自动选择latin-1(1字节/字符)或utf-16(2字节/字符)编码,纯latin-1字符串内存减半,实测堆内存节省25%~30%。

Java 9 中 String 用 byte[] 优化存储空间,不是靠你主动“使用”某个 API,而是 JVM 自动启用的底层机制——只要运行在 JDK 9 及以上版本,这个优化就默认生效,无需改代码。
底层结构从 char[] 变成 byte[] + coder
JDK 8 及之前,String 内部是 private final char[] value,每个 char 固定占 2 字节(UTF-16),哪怕只存 "abc",也要用 6 字节。
JDK 9 起改为:
-
private final byte[] value:字节数组,大小更灵活 -
private final byte coder:编码标识,0 表示 LATIN-1(单字节),1 表示 UTF-16(双字节)
Latin-1 单字节存储何时真正触发
关键不是“看起来像英文”,而是字符串中所有字符的 Unicode 码点是否都 ≤ 255(即落在 U+0000–U+00FF 范围内):
-
"Hello"、"user_id"、"2024-08-20"→ 全是 Latin-1 字符 →coder = 0→ 每字符仅占 1 字节 -
"你好"、"café"(é 在 Latin-1 中)、"??"(emoji)→ 含超范围字符 →coder = 1→ 回退 UTF-16,每字符占 2 字节
注意:é(U+00E9)属于 Latin-1,仍走单字节;但 €(U+20AC)不属于,会触发双字节模式。
实际内存节省效果明显
纯 ASCII 或 Latin-1 字符串,数据部分直接减半:
-
"Java"(4 字符):JDK 8 占 4 × 2 = 8 字节(char[]);JDK 9 占 4 × 1 + 1(coder)= 5 字节 - 大规模应用中,字符串对象通常占堆内存前三位;实测整体字符串相关内存平均下降 25%~30%
- 内存减少也间接降低 GC 压力,尤其在高字符串密度场景(如 Web 参数解析、日志拼接)
开发者需要关注什么
这个优化对日常编码几乎零侵入,但有几点值得留意:
- 不要依赖
String内部字段(如反射读value),因为 JDK 9+ 字段类型和含义已变 -
length()、charAt(i)等方法逻辑不变,JVM 内部会根据coder自动适配解码方式 - 字符串常量池、
intern()、==和.equals()行为完全兼容,无感知升级 - 若做底层字节操作(如序列化、NIO buffer 传递),需意识到内容可能以 Latin-1 或 UTF-16 打包,不能直接当成 UTF-8 处理
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











