2015-05-28 13 views
9

Mam problem, gdy próbuje konwertować bajtów do String w Javie, z kodem jak:Co dzieje się pod maską, gdy bajty są konwertowane na String w Javie?

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

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

i oryginalne bajtów nie są takie same jak te przesyłane bajty, które są odpowiednio

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

Kiedyś myślałem, że jest to spowodowane mapowaniem zestawu znaków UTF-8 dla negatywu "-3". Więc zmienię go na "-32". Ale przeniesiona tablica pozostaje taka sama!

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

Więc zdecydowanie chce wiedzieć dokładnie, co się dzieje, gdy zgłoszę new String (bajtów) :)

+2

Skąd wziął się 1, 2, -3? Czy to jest nawet poprawne UTF-8? – Necreaux

+0

Należy pamiętać, że patrzysz na numeryczną reprezentację bajtów zgodnie z Javą, w której wszystko jest podpisane. Wartość wydrukowana jako -3 jest w rzeczywistości 8-bitową wartością 0xFD lub 0b11111101. –

+0

Ponieważ bajt 0xFD odpowiada pierwszemu bajtowi kilku punktów arabskich prezentacji kodu A, może on rozszerzyć jeden z nich do odpowiedniej sekwencji UTF-8. Większość arabskich formularzy prezentacji rozwiązuje 3 bajty w UTF-8. –

Odpowiedz

9

Nie wszystkie sekwencje bajtów są poprawne w UTF-8.

UTF-8 to inteligentny schemat ze zmienną liczbą bajtów na punkt kodowy, forma każdego bajtu wskazująca liczbę innych bajtów dla tego samego punktu kodowego.

Patrz this table:

table

Teraz zobaczmy, jak ma ona zastosowanie dla {1, 2, -3}:

Bajty 1 (hex 0x01 binarny 00000001) i 2 (hex 0x02 binarny 00000010) stoją sam, bez problemu.

Byte -3 (hex 0xFD binarny 11111101) jest bajt początek sekwencji 6-bajtowy (która jest faktycznie nielegalne w current UTF-8 standard), ale swoją tablicę bajtów nie ma takiej sekwencji.

Kod UTF-8 jest nieprawidłowy. Dekoder Java UTF-8 zastępuje ten niepoprawny bajt -3 za pomocą punktu kodowania Unicode U+FFFD REPLACEMENT CHARACTER (patrz także this). w UTF-8, kod numeryczny U + FFFD to hex 0xEF 0xBF 0xBD (binarny 11101111 10111111 10111101), reprezentowany w Javie jako -17, -65, -67.

+0

Dziękuję za wyjaśnienia! – user1702713

2

Jest to linia w dokumentacji konstruktora:

Ta metoda zawsze zastępuje zniekształcone dane wejściowe i sekwencje bez możliwości modyfikacji za pomocą domyślnego łańcucha zastępczego tego zestawu znaków.

To jest zdecydowanie winowajca, ponieważ -3 jest nieprawidłowy w UTF-8. Przy okazji, jeśli jesteś naprawdę zainteresowany, zawsze możesz pobrać źródło rt.jar i debugować w nim.

4

W Java byte podpisaniu ujemne wartości są powyżej 127, i te, które stosuje się (= 0xFD -3, -32 = 0xe0) są ważne w UTF-8, tak, że obydwa izomery przekształcono do Unicode kodowy U+FFFD REPLACEMENT CHARACTER , który jest konwertowany z powrotem do UTF-8 jako 0xEF = -17, 0xBF = -65, 0xBD = -67.

Nie można oczekiwać, że wartości losowych bajtów są poprawnie interpretowane jako tekst UTF-8.

+0

To prawda, że ​​nie mogę oczekiwać, że bajty są poprawne. UTF-8 :) – user1702713

1

Zakodowane wartości, które otrzymujesz, [-17, -65, -67] odpowiadają kodowi Unicode o numerze 0xFFFD. Jeśli spojrzysz na ten punkt kodowy, the Unicode specification powie Ci, że 0XFFFD "użył do zastąpienia przychodzącego znaku, którego wartość jest nieznana lub niereprezentowalna w Unicode." I jak zauważyli inni, -3 bez żadnych jednostek kodu przekierowania UTF-8, więc ta postać jest odpowiednia.

+0

"znaki uzupełniające" powinny być "następującymi jednostkami kodowymi" lub "bajtami kontynuacyjnymi" –

+0

Dziękuję; masz absolutną rację. – dcsohl

Powiązane problemy