String.getBytes()不指定字符集会因平台默认编码差异(如Windows用GBK、Linux/macOS用UTF-8)导致字节数组不一致,引发乱码、400错误或解析失败;必须显式使用StandardCharsets.UTF_8等标准字符集并配对new String(bytes, StandardCharsets.UTF_8)。

String.getBytes() 默认行为会踩什么坑
不指定字符集时,String.getBytes() 用的是平台默认编码(比如 Windows 上是 GBK,Linux/macOS 通常是 UTF-8),同一段代码在不同机器上输出的字节数组可能完全不同。这不是 bug,但会导致序列化、网络传输或文件写入时出现乱码或解析失败。
常见错误现象:new String(bytes) 还原后中文变问号、HTTP 请求体被服务端报 400 Bad Request、日志里看到一堆 。
- 永远不要依赖无参
getBytes()处理含非 ASCII 字符的文本 - 如果必须兼容旧逻辑,至少用
StandardCharsets.UTF_8显式替代 - JDK 17+ 已将无参重载标记为
@Deprecated(forRemoval = true)
推荐写法:用 StandardCharsets 显式指定编码
从 JDK 7 开始,StandardCharsets 提供了类型安全、无需异常捕获的静态常量,比传 "UTF-8" 字符串更可靠——后者拼错会抛 UnsupportedEncodingException,而前者编译期就报错。
正确示例:
String text = "你好 world"; byte[] utf8Bytes = text.getBytes(StandardCharsets.UTF_8); byte[] gbkBytes = text.getBytes(StandardCharsets.GBK); // Windows 环境下兼容旧系统
-
StandardCharsets.UTF_8是绝大多数场景的首选,Web、API、跨语言交互都认它 -
StandardCharsets.ISO_8859_1只能表示 Latin-1 字符,中文会直接抛UnmappableCharacterException - 如果目标系统明确要求
GBK(如某些国产数据库或老 Windows 服务),才用对应常量
遇到 UnsupportedEncodingException 怎么办
这个异常只会在你用字符串名(如 "UTF-8")调用 getBytes(String charsetName) 时抛出,本质是 JVM 不支持该名称——但所有合规 JVM 都必须支持 UTF-8、UTF-16、ISO_8859_1 和 US-ASCII。
- 根本解法:改用
StandardCharsets.UTF_8,彻底避开异常 - 若必须用字符串(如配置项动态传入),先用
Charset.isSupported("xxx")校验 - 别 catch 后吞掉异常或 fallback 到平台默认编码——这等于回到第一坑
getBytes() 和 new String(byte[], ...) 的配对陷阱
用 getBytes(StandardCharsets.UTF_8) 得到的字节数组,必须用 new String(bytes, StandardCharsets.UTF_8) 才能准确还原。混用编码会丢数据,比如:
byte[] b = "café".getBytes(StandardCharsets.UTF_8); String s = new String(b, StandardCharsets.ISO_8859_1); // → "café",已损坏
- 网络传输或存储前,记录使用的
Charset(比如加个 header 或前缀) - 避免用
new String(byte[])无参构造——它又掉进平台默认编码坑 - 如果字节来源不可控(如读取未知编码的文件),优先用
InputStreamReader+CharsetDetector类库识别
实际项目里最麻烦的不是写对这一行,而是上下游约定不一致。比如前端说“我发 UTF-8”,抓包发现其实是 GBK;或者同事在配置里写 charset=utf8(缺横杠),MySQL 就当 utf8(即 utf8mb3)处理。字符集问题从来不是单点代码能解决的。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











