Java中String以UTF-16存储,网络传输必须显式编码为字节(如getBytes("UTF-8"))并用相同编码解码,否则中文必乱码;不同编码影响中文字节数与兼容性。

Java 中字符编码与网络传输的关系,核心在于“String 是 Unicode,而网络只传字节”。必须显式完成编码(String → byte[])和解码(byte[] → String),否则中文极易乱码。
字符编码是网络传输的必经转换环节
Java 内存中 String 默认按 UTF-16 存储,但 TCP/UDP 等底层协议只收发原始字节流。发送前不指定编码,就会调用系统默认 Charset(如 Windows 中可能是 GBK,Linux 多为 UTF-8),接收端若用不同编码解析,必然错乱。
- 发送端必须明确调用
str.getBytes("UTF-8"),不能依赖无参getBytes() - 接收端必须用相同编码还原:
new String(bytes, 0, len, "UTF-8") - HTTP 协议头、JSON 字符串、自定义协议报文,都需在文档或约定中固定编码格式
常见编码选择与实际影响
不同编码对中文占用字节数不同,直接影响传输效率与兼容性:
- UTF-8:中文占 3 字节,兼容 ASCII,跨平台安全,现代系统首选
- GBK:中文占 2 字节,国内旧系统常见,但无法表示生僻字或 emoji
- ISO-8859-1:单字节,不能表示中文;常被误用于“透传”场景(如先用它解出乱码字节再转 UTF-8),但属权宜之计,易出错
对象传输也绕不开编码问题
即使传输的是 Student、Order 等对象,只要走文本协议(如 JSON、XML、表单),就仍需编码:
立即学习“Java免费学习笔记(深入)”;
- JSON 库(如 Jackson、Gson)默认输出 UTF-8 字节,但写入 Socket 前仍要确认 OutputStream 是否被包装为
OutputStreamWriter并指定了 UTF-8 - 若用 DataOutputStream 直接 writeUTF(),它内部用的是 Modified UTF-8,与标准 UTF-8 不完全等价,服务端需对应处理
- 二进制序列化(如 Java Serializable)虽不显式编码,但依赖 JVM 版本和类结构一致性,生产环境不推荐
调试乱码的关键检查点
出现中文显示为问号、方块或异常符号时,逐项核对:
- 发送端
getBytes(...)用的什么编码?是否硬编码为 "UTF-8"? - 接收端
new String(...)的编码参数是否与发送端严格一致? - Socket 输入流是否被
InputStreamReader包装?其构造参数是否传了 Charset? - 抓包查看原始字节(如 Wireshark 或打印十六进制),确认发送内容本身是否已损坏


















