string.getbytes() 不指定 charset 会因平台编码差异导致乱码,windows 用 gbk、linux/macos 用 utf-8;应始终显式使用 standardcharsets.utf_8,避免字符串形式的字符集名。

String.getBytes() 不指定 Charset 就是埋雷
默认用平台编码,Windows 是 GBK,Linux/macOS 通常是 UTF-8,同一段代码在不同机器上 getBytes() 结果可能完全不同,网络传输或文件写入时直接乱码。
常见错误现象:new String(bytes) 还原失败、HTTP 请求体中文变 ?、日志里出现 字符。
- 永远显式传入
Charset,比如str.getBytes(StandardCharsets.UTF_8) - 避免用
str.getBytes("UTF-8")这种字符串形式——它抛UnsupportedEncodingException,且无法静态检查 - 如果必须兼容老 JDK(Charset.forName("UTF-8"),但要包 try-catch
new String(byte[], Charset) 的坑比想象中多
这个构造函数看似安全,实则依赖字节流“恰好合法”。UTF-8 中非法字节序列(如孤立的 0xC0)会被静默替换为 ,而不是报错。
使用场景:从 socket、文件、数据库读取原始字节后还原字符串。此时你得确认源头编码和你传入的 Charset 严格一致。
立即学习“Java免费学习笔记(深入)”;
本文档主要讲述的是Android数据格式解析对象JSON用法;JSON可以将Java对象转成json格式的字符串,可以将json字符串转换成Java。比XML更轻量级,Json使用起来比较轻便和简单。JSON数据格式,在Android中被广泛运用于客户端和服务器通信,在网络数据传输与解析时非常方便。希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
- 不要假设“反正我用了 UTF-8 就不会出错”——如果源数据其实是 GBK 编码的字节,用 UTF-8 解码必然失真
- 调试时可先打印
bytes十六进制值(Arrays.toString(bytes)),比对是否符合预期编码规则 - 需要强校验时,用
CharsetDecoder配合onMalformedInput(CodingErrorAction.REPORT)
Charset.availableCharsets() 返回的是“可用”,不是“推荐”
它列出 JVM 支持的所有字符集,包括一些冷门、过时甚至仅用于测试的(如 X-SJIS 或 ISO-2022-JP-2)。实际项目中真正该用的就几个。
性能影响:动态查表本身开销小,但若误用不支持的别名(如 "utf8" 而非 "UTF-8"),会触发类加载和注册逻辑,首次调用略慢。
- 只用
StandardCharsets.UTF_8、StandardCharsets.ISO_8859_1、StandardCharsets.US_ASCII这三个标准常量(JDK 7+) - 避免硬编码字符串如
"GBK",虽然常见,但不是所有 Android 版本或精简 JRE 都带 -
Charset.isSupported("xxx")可提前兜底,但别把它当日常判断——应该在启动时校验一次,而非每次转换都查
IO 流层面的编码设置比 String 转换更关键
很多人花大力气调 String.getBytes(),却忘了 FileWriter、OutputStreamWriter、HttpURLConnection 这些地方才是编码主战场。
典型错误:用 FileWriter 写中文,默认平台编码;用 OkHttpClient 发请求没设 Content-Type: text/plain; charset=utf-8。
-
FileWriter已淘汰,一律改用Files.write(path, content.getBytes(StandardCharsets.UTF_8))或new OutputStreamWriter(out, StandardCharsets.UTF_8) - HTTP 客户端发 JSON 时,确保 header 有
Content-Type: application/json; charset=utf-8,否则服务端可能按 ISO-8859-1 解析 - 数据库连接 URL 加
useUnicode=true&characterEncoding=UTF-8(MySQL),否则 JDBC 驱动可能忽略 Java 层的编码设置
字符集问题从来不在单个 String 对象里,而在字节流动的每个接口处——漏掉任意一环,前面所有显式指定都白搭。









