char是Unicode码元而非字节,不参与编码转换;编码转换实际发生在String与byte[]之间,需通过指定Charset显式解码/编码,处理非BMP字符时应使用codePoints()等API避免代理对破坏。

Java 中的 char 本身是 UTF-16 编码的 16 位无符号整数,它不直接对应字节,也不携带编码信息。所以“char 怎么处理编码转换”这个问题的关键在于:**char 不参与字节层面的编码转换,真正需要转换的是 String 与 byte[] 之间的双向过程,而 char 是中间的 Unicode 码元表示。**
char 本质是 Unicode 码元,不是字节
char 在 Java 中固定占 2 字节(0x0000 ~ 0xFFFF),用于表示基本多文种平面(BMP)内的 Unicode 字符。对于超出 BMP 的字符(如某些 emoji 或古汉字),Java 使用代理对(surrogate pair)——两个 char 组合表示一个 Unicode 码点(code point)。这意味着:
- 单个
char无法安全表示所有 Unicode 字符; -
char没有“编码格式”属性,它只是内存中的数值; - 你不能对
char直接调用new String(char[], charset)以外的方式做“编码转换”,因为转换必须发生在字节层面。
编码转换实际发生在 String ↔ byte[] 过程中
当你想把文本从一种编码转成另一种(比如 GBK → UTF-8),正确做法是:
- 先用源编码将字节数组解码为
String(得到 Unicode 内部表示); - 再用目标编码将该
String编码为新的字节数组。
示例:
立即学习“Java免费学习笔记(深入)”;
byte[] gbkBytes = "你好".getBytes("GBK");String str = new String(gbkBytes, "GBK"); // 解码为 Unicode 字符串
byte[] utf8Bytes = str.getBytes("UTF-8"); // 重新编码为 UTF-8 字节
注意 char[] 构造 String 时的隐式编码陷阱
如果你用 new String(char[]) 构造字符串,它不会涉及任何编码转换,只是把字符数组原样转成字符串。但若后续调用 getBytes() 且未指定 charset,会使用平台默认编码(如 Windows 上可能是 GBK),导致乱码:
- 错误写法:
new String(charArray).getBytes()—— 依赖系统默认编码,不可移植; - 正确写法:
new String(charArray).getBytes(StandardCharsets.UTF_8); - 更安全做法:始终显式传入
Charset对象,避免字符串与字节互转时歧义。
处理非 BMP 字符时要小心 char 边界
像 ?(U+1F30D)这类字符在 Java 中由两个 char(高代理 + 低代理)表示。如果用 String.toCharArray() 后按单个 char 处理(比如遍历、截断、替换),可能破坏代理对,导致显示为 或解析异常。
- 推荐用
String.codePoints()流式遍历 Unicode 码点; - 或用
String.offsetByCodePoints()、Character.isSurrogatePair()等 API 安全操作; - 避免基于
char下标做文本切分,改用String.substring()(它按 code point 边界安全处理)。


















