2015-05-28 71 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

相關問題