String不可变,编码转换本质是字节与字符的映射;乱码源于编解码不匹配,需明确原始字节真实编码,通过“字节→正确解码→目标编码→新String”安全转换。

Java 中的 String 本身是不可变的,但“转换编码”实际是指:**将已知编码的字节数组按目标编码重新解码为新的 String,或把 String 按目标编码编码为字节数组再解码**。乱码的根本原因是**编码与解码不匹配**,而非 String 是否可变。关键在于明确原始字节的真实编码,并用正确方式重建 String。
确认原始字节的真实编码
String 对象内部以 UTF-16 存储,但它的来源决定是否乱码:
- 如果 String 来自文件、网络、数据库等外部输入,需知道它最初是用什么编码(如 GBK、ISO-8859-1、UTF-8)写入的字节
- 若用错编码读取(比如用 UTF-8 解码本是 GBK 的字节),String 内容已损坏,后续任何转换都无法完全恢复
- 常见误操作:直接用
new String(bytes)(依赖平台默认编码),极易出错
安全转换编码的正确步骤
必须经过「字节数组 → 正确编码解码为 String → 目标编码编码为字节 → 目标编码解码为新 String」这一步骤链:
-
已知原始编码(如 GBK),想转成 UTF-8 String:
byte[] gbkBytes = ...; // 原始 GBK 字节
String temp = new String(gbkBytes, "GBK"); // 用 GBK 正确还原为 String
byte[] utf8Bytes = temp.getBytes("UTF-8"); // 转为 UTF-8 字节
String utf8Str = new String(utf8Bytes, "UTF-8"); // (可选)验证,实际中 temp 就已是语义正确的 UTF-16 String - 不确定原始编码?优先查源头协议或元数据(HTTP Content-Type、XML 声明、数据库连接配置)
-
绝对避免:
new String(bytes, "ISO-8859-1").getBytes("UTF-8")这类“假转换”,只是字节映射,不解决语义错误
处理常见乱码场景(如 URL 参数、表单提交)
Web 场景中乱码多因容器/浏览器编码不一致:
- Tomcat 8+ 默认使用 UTF-8,但若前端用 GBK 提交,需在 request 上显式设置:
request.setCharacterEncoding("GBK");
String param = request.getParameter("name"); // 此时 param 才是正确内容 - JSP 页面需声明:
,且 HTML 加 - 数据库连接 URL 显式指定编码:
useUnicode=true&characterEncoding=UTF-8
工具建议:用 StandardCharsets 避免字符串编码名拼写错误
用 JDK 7+ 的静态常量代替字符串字面量,更安全、更高效:
- ✅ 推荐:
new String(bytes, StandardCharsets.UTF_8) - ❌ 避免:
new String(bytes, "UTF-8")(可能抛 UnsupportedEncodingException,且易拼错) - 编码转换本质是字节与字符的映射关系,String 不可变反而是优势——每次转换都生成新对象,避免隐式修改
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











