Ist die Größe des Zeichens in Java 2 Bytes nicht?

Ich habe RandomAccessFile , um ein byte aus einer Textdatei zu lesen.

 public static void readFile(RandomAccessFile fr) { byte[] cbuff = new byte[1]; fr.read(cbuff,0,1); System.out.println(new String(cbuff)); } 

Warum sehe ich einen vollen Charakter, der dadurch gelesen wird?

Ein Zeichen repräsentiert ein Zeichen in Java (*) . Es ist 2 Byte groß (zumindest schlägt der gültige Wertebereich vor).

Das bedeutet nicht unbedingt, dass jede Darstellung eines Zeichens 2 Byte lang ist. Tatsächlich reservieren viele Kodierungen nur 1 Byte für jedes Zeichen (oder verwenden 1 Byte für die gebräuchlichsten Zeichen).

Wenn Sie den Konstruktor String(byte[]) aufrufen, fragen Sie Java, das byte[] in einen String zu konvertieren, indem Sie die Standardcodierung der Plattform verwenden. Da die Standardcodierung der Plattform normalerweise eine 1-Byte-Codierung wie ISO-8859-1 oder eine Codierung mit variabler Länge wie UTF-8 ist, kann sie dieses 1-Byte problemlos in ein einzelnes Zeichen konvertieren.

Wenn Sie diesen Code auf einer Plattform ausführen, die UTF-16 (oder UTF-32 oder UCS-2 oder UCS-4 oder …) als Plattform-Standardcodierung verwendet, erhalten Sie kein gültiges Ergebnis (Sie erhalten ein String , der stattdessen das Unicode-Ersatzzeichen enthält).

Das ist einer der Gründe, warum Sie nicht von der Standardkodierung der Plattform abhängig sein sollten: Beim Konvertieren zwischen byte[] und char[] / String oder zwischen InputStream und Reader oder zwischen OutputStream und Writer sollten Sie immer angeben, welche Kodierung Sie verwenden möchten. Wenn Sie dies nicht tun, wird Ihr Code plattformabhängig sein.

(*) Das ist nicht ganz richtig: Ein char für einen UTF-16-Codepunkt. Ein oder zwei UTF-16-Codepunkte stellen einen Unicode-Codepunkt dar. Ein Unicode-Codepunkt repräsentiert normalerweise ein Zeichen, aber manchmal werden mehrere Unicode-Codepunkte verwendet, um ein einzelnes Zeichen zu bilden. Aber die obige Annäherung ist nah genug, um das Thema zu diskutieren.

Java speichert alle seine “Zeichen” intern als zwei Bytes. Wenn sie jedoch zu Strings usw. werden, hängt die Anzahl der Bytes von Ihrer Codierung ab.

Einige Zeichen (ASCII) sind einzelne Byte, aber viele andere sind Multi-Byte.

Java unterstützt Unicode, also nach:

Java-Zeichendokumente

Der unterstützte Maximalwert ist “\ uFFFF” (Hex FFFF, Dez. 65535) oder 11111111 11111111 Binär (zwei Byte).

Der Konstruktor String(byte[] bytes) übernimmt die Bytes aus dem Puffer und codiert sie in Zeichen.

Es verwendet den Standard-Zeichensatz der Plattform, um Bytes in Zeichen zu codieren. Wenn Sie wissen, dass Ihre Datei Text enthält, der in einem anderen Zeichensatz codiert ist, können Sie die String(byte[] bytes, String charsetName) , um die korrekte Codierung (von Byte zu Zeichen) zu verwenden.

In der ASCII-Textdatei ist jedes Zeichen nur ein Byte

Ihre Datei enthält ASCII-Zeichen, die in nur 1 Byte codiert sind. Wenn die Textdatei ein Nicht-ASCII-Zeichen enthält, z. B. 2-Byte-UTF-8, erhalten Sie nur das erste Byte, nicht das ganze Zeichen.

Es gibt hier einige gute Antworten, aber ich möchte darauf hinweisen, dass der jvm frei ist, einen char-Wert in jeder Größe> 2 Bytes zu speichern.

Auf vielen Architekturen gibt es eine Strafe für das Ausführen eines nicht ausgerichteten Speicherzugriffs, so dass ein Zeichen leicht auf 4 Bytes aufgefüllt werden kann. Ein flüchtiges Zeichen könnte sogar auf die Größe der CPU-Cache-Zeile aufgefüllt werden, um eine falsche Freigabe zu verhindern. https://en.wikipedia.org/wiki/False_sharing

Für neue Java-Programmierer mag es nicht intuitiv sein, dass ein Zeichen-Array oder eine Zeichenfolge NICHT einfach aus mehreren Zeichen besteht. Sie sollten Strings und Arrays deutlich von “multiple characters” lernen und darüber nachdenken.

Ich möchte auch darauf hinweisen, dass Java-Zeichen oft missbraucht werden. Die Leute wissen nicht, dass sie Code schreiben, der Codepoints mit einer Länge von mehr als 16 Bit nicht korrekt verarbeiten kann.