2013-07-28 23 views
25

Jeśli skonwertuję znak na byte, a następnie z powrotem na char, ta postać w tajemniczy sposób znika i staje się czymś innym. Jak to jest możliwe?Konwersja bajtów i znaków w języku Java

Jest to kod:

char a = 'È';  // line 1  
byte b = (byte)a; // line 2  
char c = (char)b; // line 3 
System.out.println((char)c + " " + (int)c); 

Do linii 2 wszystko jest w porządku:

  • W wierszu 1 mogłem wydrukować "a" w konsoli i byłoby pokazać "e".

  • W linii 2 mogłem wydrukować "b" w konsoli i pokazywałoby -56, czyli 200 ponieważ bajt jest podpisany. A 200 to "È". Więc nadal jest w porządku.

Co jest nie tak w linii 3? "c" staje się czymś innym, a program drukuje ? 65480. To coś zupełnie innego.

Co powinienem napisać w wierszu 3, aby uzyskać poprawny wynik?

+4

"Bajt" to "8 bitów".'char' to' 16 bit'. Masz pomysł? –

+0

char pobiera 2 bajty. – Ankit

+0

@RohitJain A znak - przez co rozumiem kodowy kod Unicode - może zająć dwa znaki lub cztery bajty. Co więcej, kto wie, czym jest normalizacja? Ciąg '" È "' może sam zawierać jeden lub dwa punkty kodowe, zależnie od tego, czy ma on odpowiednio postać Normalizacji C lub D. – tchrist

Odpowiedz

44

Znak w języku Java jest jednostką kodową Unicode, która jest traktowana jako liczba bez znaku. Więc jeśli wykonać c = (char)b wartość masz jest 2^16 - 56 lub 65.536 - 56.

Albo dokładniej, bajt jest najpierw przekształca się liczba całkowita ze znakiem o wartości 0xFFFFFFC8 wykorzystaniem znak rozszerzenie w rozszerzającej się konwersji . To z kolei jest następnie zwężane do 0xFFC8 podczas odlewania do char, co przekłada się na liczbę dodatnią 65480.

od specyfikacji język:

5.1.4. Widening and Narrowing Primitive Conversion

Pierwszy bajt jest przekształcany do int poprzez poszerzenie prymitywny konwersji (§5.1.2) czym powstałą Int przekształca się w char przez zawężenie prymitywnej konwersji (§5.1.3).


Aby uzyskać odpowiedni punkt zastosowanie char c = (char) (b & 0xFF) który najpierw przekształca wartość bajtu b do dodatnia 200 za pomocą maski, wyzerowanie górę 24 bitów, po konwersji: 0xFFFFFFC8 się 0x000000C8 albo liczbę dodatnią 200 w ułamkach dziesiętnych.


Powyżej jest bezpośrednim wyjaśnienie tego, co się dzieje podczas konwersji pomiędzy byte, int i char prymitywnych typów.

Jeśli chcesz do kodowania/dekodowania znaków z bajtów, należy Charset, CharsetEncoder, CharsetDecoder lub jedną z metod typu convenience, takich jak new String(byte[] bytes, Charset charset) lub String#toBytes(Charset charset). Możesz uzyskać zestaw znaków (taki jak UTF-8 lub Windows-1252) z StandardCharsets.

+3

Właściwie Java 'char' nie jest kodem w standardzie Unicode * ***. Jest to jednostka kodowa UTF-16 * ** ***. Aby faktycznie reprezentować dowolny "znak" Unicode (przez co rozumiem faktyczny punkt kodowy), Java 'char' nie jest wystarczająco dobry: musisz użyć' int' (efektywnie dając ci UTF-32), który może zająć do dwóch znaków w starszej notacji UTF-16. Właśnie dlatego wszystko ma API 'codePointAt', nie tylko zły stary 'charAt' API. – tchrist

+1

@tchrist tak, zmieniło się trochę, gdy Unicode przekroczył granicę 64Ki. –

+0

Dlaczego "char c = (char) (b & 0xFF)" używa tylko jednego bajtu, gdy znaki Java mają być dwa bajty? – statueofmike

Powiązane problemy