Java字符串编码转换本质是“先解码再重新编码”的两步操作:先用new String(bytes, charset)按原始编码解码为UTF-16 String,再用String.getBytes(targetCharset)按目标编码重新编码为字节,最后用new String(…, targetCharset)得到目标编码字符串;必须显式指定Charset,禁用无参方法。

Java 中字符串编码转换主要靠 String.getBytes(Charset) 和 new String(byte[], Charset) 配合完成,核心是明确“原始编码”和“目标编码”,不能直接在 String 内部改编码(String 在 JVM 里始终是 UTF-16),本质是“先解码再重新编码”的两步操作。
明确原始编码:用 getBytes 得到字节数组
String.getBytes() 默认用平台默认编码(不推荐),应显式传入 Charset(如 StandardCharsets.UTF_8 或 Charset.forName("GBK")),表示“把当前 String 按指定编码规则编码成字节”。这一步不是转换,而是**序列化**——把内存中的 UTF-16 字符转为对应编码的字节流。
- 例如:
"你好".getBytes(StandardCharsets.UTF_8)→ 得到 UTF-8 编码的 6 个字节 - 若字符串原本来自 GBK 字节但被错误按 UTF-8 解析成了 String,此时调用
getBytes(StandardCharsets.UTF_8)会得到错误的字节,必须先用 GBK 重新“还原”
指定目标编码:用 new String(byte[], Charset) 重建字符串
new String(byte[], Charset) 表示“把字节数组按指定编码规则解码成字符”,这是**反序列化**过程。它把字节解释为某种编码下的文本,再转成 JVM 内部的 UTF-16 String。
- 例如:
new String(bytes, StandardCharsets.ISO_8859_1)把字节按 Latin-1 解释为字符 - 关键:这里的
Charset必须与生成bytes时用的编码逻辑匹配,否则出现乱码(如用 UTF-8 的字节却按 GBK 解,必然错)
典型转换场景:ISO-8859-1 → UTF-8(常见于 HTTP 参数或旧系统)
假设你收到一个用 ISO-8859-1 编码的字节数组,想转成正确显示的 UTF-8 字符串:
立即学习“Java免费学习笔记(深入)”;
- 先用 ISO-8859-1 解码字节 → 得到中间 String(此时内容可能已乱,但字节映射一对一,可逆)
- 再把这个 String 按 ISO-8859-1 重新编码成字节 → 得到原始字节
- 最后用 UTF-8 解码这些字节 → 得到正确 UTF-8 字符串
代码写法:
byte[] isoBytes = ...; // 原始 ISO-8859-1 字节 String temp = new String(isoBytes, StandardCharsets.ISO_8859_1); byte[] utf8Bytes = temp.getBytes(StandardCharsets.ISO_8859_1); String utf8Str = new String(utf8Bytes, StandardCharsets.UTF_8);
更简洁写法(等价):
String utf8Str = new String(isoBytes, StandardCharsets.ISO_8859_1)
.getBytes(StandardCharsets.ISO_8859_1),
StandardCharsets.UTF_8);
避坑提醒:别用平台默认编码,别漏掉 Charset 参数
String.getBytes() 和 new String(byte[]) 无参版本依赖系统 default charset(Windows 常是 GBK,Linux/macOS 常是 UTF-8),跨环境必出问题。
- 始终使用
StandardCharsets.UTF_8、StandardCharsets.GBK等标准常量 - 处理外部数据(文件、网络、数据库)时,务必确认其真实编码,而不是猜或忽略
- IDE 或控制台输出乱码,往往是终端/控制台编码设置不匹配,不是代码问题


















