java字符串内存中用utf-16编码,char存unicode码点值(如“中”为0x4e2d),utf-8仅用于io时的字节转换;bmp外字符需代理对,遍历应使用codepoints()避免charat(i)错误。

Java 本身不直接用 UTF-8 存储字符串——它用 UTF-16 编码在内存中保存中文字符,UTF-8 只用于输入输出(如文件读写、网络传输)时的字节序列表示。
Java 字符串内部:UTF-16 编码
Java 的 String 和 char 类型基于 UTF-16:
- char 是 16 位无符号整数(0–65535),对应一个 UTF-16 编码单元(code unit)
- 绝大多数中文汉字(如“中”“你”“好”)的 Unicode 码点落在基本多语言平面(BMP),范围是 U+4E00–U+9FFF,每个只需 1 个 char 表示
例如:“中”的 Unicode 码点是 U+4E2D,在 Java 中存为(char)0x4E2D,即十进制 20013 - 少数生僻字或 emoji(如 ?、?)超出 BMP(U+10000 起),需用两个 char 组成代理对(surrogate pair),共占 4 字节
UTF-8 是外部编码,用于字节流转
当你调用 str.getBytes(StandardCharsets.UTF_8),Java 才把 UTF-16 内存数据按 UTF-8 规则转换成字节数组:
- 每个中文字符(BMP 范围内)生成 3 个字节
例如:“中” → UTF-8 字节为[0xE4, 0xB8, 0xAD](十进制 [-28, -72, -83]) - 这个过程是编码(encode),不是存储;字节不会进入 String 对象内部
- 反之,用
new String(bytes, StandardCharsets.UTF_8)是解码(decode):把 UTF-8 字节流还原为 UTF-16 的 String
为什么 char 能存中文,尽管 UTF-8 要 3 字节?
关键在于混淆了「存储编码」和「传输编码」:
- UTF-8 的 3 字节是面向字节流的外部表示,解决的是磁盘/网络怎么传的问题
- char 存的是 Unicode 码点值(如 0x4E2D),不是 UTF-8 字节本身
- 所以“中”在 char 里是 一个数字 20013,不是三个字节;JVM 按 UTF-16 解释它,再按需要转成 UTF-8 输出
实际开发中要注意的点
- 读文件或接收 HTTP 请求时,必须显式指定
StandardCharsets.UTF_8,否则可能用平台默认编码(如 Windows-1252),导致中文乱码 - 不要用
new String(bytes)无参构造——它依赖系统默认编码,不可移植 - 遍历字符串别用
charAt(i)处理可能含代理对的文本;改用codePoints()流或String.iterateCodePoints()(Java 15+)确保按 Unicode 字符(而非 char 单元)处理
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











