Java中String内部用UTF-16存储,乱码源于编解码字符集不一致;应使用getBytes(Charset)和new String(byte[], Charset)显式指定统一编码,避免默认编码导致跨平台问题。

Java中String本身不存储字符集信息,它内部用UTF-16表示字符。所谓“乱码”,本质是字节流编码与解码时使用的字符集不一致。要正确获取指定字符集的字节流,关键不是“转换字符串”,而是明确:String → 按指定charset编码 → byte[]。
用getBytes(Charset)安全获取字节流
推荐使用带Charset参数的getBytes(Charset)方法,避免依赖平台默认编码(如Windows上是GBK,Linux/macOS上常为UTF-8):
-
正确写法:
"你好".getBytes(StandardCharsets.UTF_8)或"你好".getBytes(Charset.forName("GBK")) -
避免写法:
"你好".getBytes()—— 使用系统默认编码,跨环境极易出错 - 若需兼容旧API(如JDK 7以下),可用
Charset.forName("UTF-8")代替StandardCharsets
注意new String(byte[], Charset)的反向操作
从字节流还原String时,必须用**与编码时完全相同的Charset**,否则必然乱码:
- 编码:
byte[] bs = "你好".getBytes(StandardCharsets.UTF_8); - 解码:
String s = new String(bs, StandardCharsets.UTF_8);✅ - 错误解码:
new String(bs, StandardCharsets.GBK)❌ 得到“浣犲ソ”之类乱码
网络/IO场景中务必显式指定编码
HTTP请求头、文件读写、Socket传输等场景,不能依赖隐式编码:
- 写文件时:
Files.write(path, content.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE); - HTTP响应头应设:
Content-Type: text/html; charset=utf-8 - 数据库连接URL中加上
useUnicode=true&characterEncoding=UTF-8(MySQL)
调试乱码:先确认原始字节再比对编码
遇到乱码别猜,直接打印字节序列,对照编码表验证:
- 打印UTF-8字节:
System.out.println(Arrays.toString("你好".getBytes(StandardCharsets.UTF_8)));→[[-28, -67, -96, -27, -91, -67]] - 打印GBK字节:
System.out.println(Arrays.toString("你好".getBytes(Charset.forName("GBK"))));→[[-60, -29, -70, -61]] - 字节不同,说明编码方式不同;字节相同但显示乱码,说明解码端用了错误Charset










