java中string内存恒为utf-16,编码转换关键在解码与编码两步:先用源编码(如utf-8)构造string,再用目标编码(如gbk)获取字节数组;需依来源判别编码,禁用盲目猜测。

Java 中区分和转换 UTF-8 与 GBK,关键不在 String 本身,而在字节与字符之间的“两次桥梁”——一次解码、一次编码。String 在内存里永远是 UTF-16,它不带编码属性;真正起作用的是你读入字节时用的 Charset,以及写出字节时指定的 Charset。
怎么一眼看出当前数据是 UTF-8 还是 GBK?
不能靠看字符串内容,得看它的来源:
- 从 HTTP 响应头(Content-Type: text/html; charset=utf-8)或响应体 BOM 判断
- 从文件保存方式判断:Windows 记事本选“ANSI”保存 → 大概率是 GBK;选“UTF-8 无签名”→ 是 UTF-8
- 从数据库连接 URL 或字段 collation 看:useUnicode=true&characterEncoding=utf8 表明走 UTF-8;gbk 或 cp936 表明走 GBK
- 直接拿到 byte[] 时,若不确定来源,可尝试用两种 Charset 分别 new String(...),观察是否乱码(如显示为 “” 或 “锟斤拷”),但该方法仅作辅助,不可用于生产逻辑
UTF-8 字节数组转 GBK 字节数组(正确写法)
前提:你手上有 确实是 UTF-8 编码的 byte[],比如从网络请求、UTF-8 文件读取得到。
- 先用 UTF-8 把字节数组“还原”成语义正确的 String:new String(utf8Bytes, "UTF-8")
- 再让这个 String 按 GBK 规则“重新编码”为字节:str.getBytes("GBK")
完整示例:
String str = new String(utf8Bytes, "UTF-8");
byte[] gbkBytes = str.getBytes("GBK");
GBK 字节数组转 UTF-8 字节数组(同理)
逻辑完全对称,只是调换编码名:
- 用 GBK 解码原始字节 → 得到正确 String
- 再用 UTF-8 编码该 String → 得到新字节
示例:
byte[] gbkBytes = ... ; // 确认是 GBK 编码String str = new String(gbkBytes, "GBK");
byte[] utf8Bytes = str.getBytes("UTF-8");
常见错误写法及为什么错
这些写法表面能跑通,但极易导致乱码或数据损坏:
- new String(bytes, "GBK").getBytes("UTF-8") —— 如果 bytes 实际是 UTF-8 编码,却用 GBK 解,第一步就语义错乱,后续全错
- new String(bytes, "UTF-8").getBytes("UTF-8") —— 看似绕一圈,实际多余;但如果 bytes 来源不明,这步反而掩盖问题
- 忽略异常捕获:getBytes() 和 String 构造器都可能抛 UnsupportedEncodingException,Java 8+ 虽内置 UTF-8/GBK,但仍建议显式 try-catch 或使用 StandardCharsets(更安全)
推荐升级写法(Java 7+):
String str = new String(utf8Bytes, StandardCharsets.UTF_8);byte[] gbkBytes = str.getBytes(StandardCharsets.GBK);
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











