2013-07-28 5 views
25

Wenn ich ein Zeichen zu byte und dann zurück zu char umwandle, verschwindet dieser Charakter auf mysteriöse Weise und wird etwas anderes. Wie ist das möglich?Byte und Zeichenumwandlung in Java

Dies ist der Code:

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

Bis Linie 2 ist alles in Ordnung:

  • In Zeile 1 konnte ich "a" in der Konsole aus und es würde zeigen, "E".

  • In Zeile 2 konnte ich "b" in der Konsole drucken und es würde -56 angezeigt, das ist 200, da Byte signiert ist. Und 200 ist "È". Es ist also immer noch in Ordnung.

Aber was ist falsch in Zeile 3? "c" wird zu etwas anderem und das Programm druckt ? 65480. Das ist etwas ganz anderes.

Was sollte ich in Zeile 3 schreiben, um das richtige Ergebnis zu erhalten?

+4

Ein 'Byte' ist' 8 Bit'.'char' ist' 16 bit'. Hast du die Idee? –

+0

char dauert 2byte. – Ankit

+0

@RohitJain Und ein Zeichen - mit dem ich einen Unicode-Code-Punkt meine - kann zwei Zeichen oder vier Bytes dauern. Wer weiß außerdem, in welcher Normalisierung Form ist? Die Zeichenkette "" kann selbst einen oder zwei Codepunkte umfassen, abhängig davon, ob sie sich in der Normalisierungsform C oder D befindet. – tchrist

Antwort

44

Ein Zeichen in Java ist eine Unicode-Code-Unit, die als vorzeichenlose Zahl behandelt wird. Also, wenn Sie c = (char)b durchführen der Wert Sie erhalten, ist 2^16 - 56 oder 65536 - 56

Oder genauer gesagt, ist das Byte zuerst mit dem Wert auf eine ganze Zahl mit Vorzeichen umgewandelt 0xFFFFFFC8 mit Vorzeichenerweiterung in einer erweiternde Konvertierung . Dies wiederum wird dann auf 0xFFC8 reduziert, wenn es auf einen char geworfen wird, was sich in die positive Zahl 65480 umwandelt.

aus der Sprache Spezifikation:

5.1.4. Widening and Narrowing Primitive Conversion

Zuerst wird das Byte in einen int über erweiternden primitive Umwandlung umgewandelt wird (§5.1.2), und dann die resultierende int a umgewandelt char durch Verengung primitive Konvertierung (§5.1.3).


nach rechts zeigen Verwendung char c = (char) (b & 0xFF) zu erhalten, die zunächst den Bytewert von b an die positive ganze Zahl konvertiert 200 unter Verwendung einer Maske, die oberen 24 Bits nach der Umwandlung Nullung: 0xFFFFFFC8 wird 0x000000C8 oder die positive Zahl 200 in Dezimalzahlen.


Oben ist eine direkte Erklärung dessen, was zwischen den byte während der Umwandlung geschieht, int und char Urtyp.

Wenn Sie möchten, kodieren/dekodieren Zeichen von Bytes, verwenden Charset, CharsetEncoder, CharsetDecoder oder eine der Bequemlichkeit Methoden wie new String(byte[] bytes, Charset charset) oder String#toBytes(Charset charset). Sie können den Zeichensatz (z. B. UTF-8 oder Windows-1252) von StandardCharsets abrufen.

+3

Eigentlich ist ein Java 'char' kein Unicode * Code ** Punkt ***. Es ist ein UTF-16 * Code ** Einheit ***. Um tatsächlich ein beliebiges Unicode-Zeichen darzustellen (womit ich einen tatsächlichen Codepunkt meinen möchte), ist ein Java-Zeichen nicht gut genug: Sie müssen ein int verwenden, um UTF-32 zu erhalten zu zwei Zeichen in UTF-16-Notation. Aus diesem Grund hat alles eine "codePointAt" API, nicht nur die schlechte alte 'charAt' API. – tchrist

+1

@tchrist yeah, das hat sich ein wenig geändert, als Unicode über den 64Ki-Rahmen ging. –

+0

Warum ist 'char c = (char) (b & 0xFF)' nur ein einzelnes Byte, wenn Java-Zeichen zwei Bytes sein sollen? – statueofmike