在Java中将字节转换为String时会发生什么?

时间:2015-05-28 15:33:57

标签: java string unicode utf-8 byte

尝试在Java中将字节转换为String时出现问题,代码如下:

byte[] bytes = {1, 2, -3};

byte[] transferred = new String(bytes, Charsets.UTF_8).getBytes(Charsets.UTF_8);

且原始字节与传输的字节不同,分别为

[1, 2, -3]
[1, 2, -17, -65, -67]

我曾经认为这是由于UTF-8字符集映射为负“-3”。所以我把它改成“-32”。但转移的阵列保持不变!

[1, 2, -32]
[1, 2, -17, -65, -67] 

所以我非常想知道在调用new String(bytes)时会发生什么:)

4 个答案:

答案 0 :(得分:9)

并非所有字节序列在UTF-8中都有效。

UTF-8是一个智能方案,每个代码点的字节数可变,每个字节的形式表示相同代码点的其他字节数。

请参阅this table

table

现在让我们看看它如何适用于您的{1, 2, -3}

字节1(十六进制0x01,二进制00000001)和2(十六进制0x02,二进制00000010)独立,没问题

字节-3(十六进制0xFD,二进制11111101)是一个6字节序列的起始字节(在current UTF-8 standard中实际上是非法的),但是字节数组没有这样的序列。

您的UTF-8无效。 Java UTF-8解码器用Unicode代码点U+FFFD REPLACEMENT CHARACTER替换此无效字节-3(另请参阅this)。在UTF-8中,代码点U + FFFD是十六进制0xEF 0xBF 0xBD(二进制11101111 10111111 10111101),在Java中表示为-17, -65, -67

答案 1 :(得分:4)

在Java中,byte已签名,其中负值大于127.您使用的那些(-3 = 0xFD,-32 = 0xE0)在UTF-8中无效,因此它们都转换为Unicode代码点U+FFFD REPLACEMENT CHARACTER,转换回UTF-8为0xEF = -17,0xBF = -65,0xBD = -67。

您不能指望随机字节值被正确解释为UTF-8文本。

答案 2 :(得分:2)

构造函数的文档中有一行:

  

此方法始终使用此charset的默认替换字符串替换格式错误的输入和不可映射字符序列。

这绝对是罪魁祸首,因为-3在UTF-8中无效。顺便说一句,如果您真的感兴趣,可以随时下载rt.jar的源代码并调试它。

答案 3 :(得分:1)

您获得的编码值[-17,-65,-67]对应于Unicode代码点0xFFFD。如果您查找该代码点,the Unicode specification会告诉您0XFFFD“用于替换其值在Unicode中未知或不可表示的传入字符。”正如其他人所指出的那样,没有任何后续代码单元的-3被破坏了UTF-8,所以这个角色是合适的。