You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何UTF-8下byte[]→String→byte[]输入输出不一致?ISO_8859_1是否始终一致?

问题解答

为什么UTF-8下byte[]→String→byte[]会出现输入输出差异?

没错,这确实和UTF-8的可变宽度编码特性密切相关,但更核心的原因是UTF-8对字节序列的合法性有严格要求。

咱们先拆解UTF-8的编码逻辑:它用1-4个字节表示一个Unicode字符,而且不是随便组合的字节都算合法序列。比如:

  • 单字节字符的最高位必须是0(范围0x00-0x7F)
  • 多字节字符的首字节以110、1110、11110开头,后续字节必须以10开头

如果你的inputBytes里包含不符合规则的字节(比如单独的0xFF,或者半截的多字节序列),把它转成String时,Java会自动把这些非法UTF-8字节替换成Unicode的替换字符�(U+FFFD)。等你再把这个String转回byte[]时,替换字符会被编码成UTF-8格式的三个字节:0xEF 0xBF 0xBD,这自然和原输入字节不一样,测试用例也就失败了。

举个直观的代码例子:

import java.util.Arrays;
import java.nio.charset.StandardCharsets;

public class CharsetDemo {
    public static void main(String[] args) {
        byte[] inputBytes = new byte[]{(byte) 0xFF}; // 非法UTF-8单字节
        String str = new String(inputBytes, StandardCharsets.UTF_8);
        byte[] outputBytes = str.getBytes(StandardCharsets.UTF_8);
        
        // 对比结果:inputBytes是[0xFF],outputBytes是[0xEF, 0xBF, 0xBD]
        System.out.println("输入字节:" + Arrays.toString(inputBytes));
        System.out.println("输出字节:" + Arrays.toString(outputBytes));
    }
}

为什么ISO_8859_1下转换不会有问题?

ISO_8859_1(又称Latin-1)是单字节固定宽度编码,它的设计逻辑就是把每个字节(0x00-0xFF)直接映射到Unicode的U+0000到U+00FF字符。也就是说:

  • 任何字节值在ISO_8859_1里都是合法编码
  • 转成String时,每个字节对应唯一的Unicode字符,没有替换逻辑
  • 转回byte[]时,每个Unicode字符又会还原成原来的字节值

不管你的inputBytes数组多大、包含什么字节,这个1:1的映射关系都不会断裂,所以测试总能通过。

附加问题:ISO_8859_1的byte[]→String→byte[]转换是否始终一致?

是的,绝对一致。

因为ISO_8859_1的编码空间刚好覆盖了所有可能的字节值(0x00到0xFF),每个字节和Unicode字符是严格一一对应的,不存在任何需要替换的非法序列。只要你全程使用ISO_8859_1字符集进行转换,输入和输出的byte[]就会完全相同,没有任何损耗或变化。


内容的提问来源于stack exchange,提问作者PresentProgrammer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 04:31:19