2015-05-28 28 views
9

试图字节转换为字符串在Java中,当我有一个问题,有这样的代码:在Java中将字节转换为字符串时发生了什么?

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] 

所以我强烈地想知道我什么时候叫新的字符串(字节):)

+2

你从哪里拿出1,2,-3?那甚至是有效的UTF-8? – Necreaux

+0

请记住,您正在查看根据Java对所有内容进行签名的字节的数字表示形式。打印为-3的值实际上是8位值0xFD或0b11111101。 –

+0

由于字节0xFD对应于阿拉伯语表示形式代码点的第一个字节,因此它可能会将其中一个扩展为正确的UTF-8序列。大多数阿拉伯语演示文稿表单都以UTF-8格式解析为3个字节。 –

回答

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(另请参阅this)替换此无效字节-3。在UTF-8中,代码点U + FFFD是十六进制的0xEF 0xBF 0xBD(二进制11101111 10111111 10111101),用Java表示为-17, -65, -67

+0

谢谢你的解释! – user1702713

2

有构造函数的文档中的线究竟会发生什么:

此方法始终用这个字符集的默认替换字符串替换畸形输入和不可映射字符序列。

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

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文本。

+0

这是正确的,我不能指望任何字节是正确的UTF-8 :) – user1702713

1

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

+0

“后续字符”应该是“后续代码单元”或“延续字节” –

+0

谢谢;你是绝对正确的。 – dcsohl

相关问题