it-roy-ru.com

Разве размер символа в Java не равен 2 байтам?

Я использовал RandomAccessFile для чтения byte из текстового файла.

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

Почему я вижу один полный символ, читаемый этим?

43
Shrinath

char представляет символ в Java (*), Он имеет размер 2 байта (по крайней мере, это соответствует допустимому диапазону значений).

Это не обязательно означает, что каждое представление символа имеет длину 2 байта. Фактически, многие кодировки резервируют только 1 байт для каждого символа (или используют 1 байт для наиболее распространенных символов).

Когда вы вызываете конструктор String(byte[]), вы просите Java преобразовать byte[] в String, используя кодировку платформы по умолчанию. Поскольку кодировка платформы по умолчанию обычно представляет собой 1-байтовую кодировку, такую ​​как ISO-8859-1, или кодировку переменной длины, такую ​​как UTF-8, она может легко преобразовать этот 1 байт в один символ.

Если вы запустите этот код на платформе, которая использует UTF-16 (или UTF-32 или UCS-2 или UCS-4 или ...) в качестве кодировки по умолчанию для платформы, то вы не получите действительный результат (вы получите String, содержащий взамен символ замены Unicode).

Это одна из причин, по которой вы не должны зависеть от кодировки платформы по умолчанию: при преобразовании между byte[] и char[]String или между InputStream и Reader или между OutputStream и Writer вы должны всегда указать, какую кодировку вы хотите использовать. Если вы этого не сделаете, то ваш код будет зависеть от платформы.

(*) это не _/полностью верно: char представляет кодовую точку UTF-16. One или two кодовые точки UTF-16 представляют кодовую точку Unicode. Кодовая точка Unicode обычно представляет символ, но иногда несколько кодовых точек Unicode используются для создания одного символа. Но приведенное выше приближение достаточно близко, чтобы обсудить данную тему.

105
Joachim Sauer

Java хранит все свои "символы" внутри как два байта. Однако, когда они становятся строками и т.д., Количество байтов будет зависеть от вашей кодировки.

Некоторые символы (ASCII) являются однобайтовыми, но многие другие являются многобайтовыми.

Java поддерживает Unicode, таким образом, согласно:

Документы по символам Java

Максимальное поддерживаемое значение: «\ uFFFF» (шестнадцатеричный FFFF, декабрь 65535) или 11111111 двоичный файл 11111111 (два байта).

13
Michael

Конструктор String(byte[] bytes) берет байты из буфера и кодирует их в символы.

Он использует кодировку платформы по умолчанию для кодирования байтов в символы. Если вы знаете, что ваш файл содержит текст, закодированный в другой кодировке, вы можете использовать функцию String(byte[] bytes, String charsetName), чтобы использовать правильную кодировку (от байтов до символов).

6
Andreas_D

В текстовом файле ASCII каждый символ занимает всего один байт

1
RemoteSojourner

Похоже, ваш файл содержит символы ASCII, которые кодируются всего 1 байтом. Если текстовый файл содержит не-ASCII символ, например, 2-байтный UTF-8, тогда вы получите только первый байт, а не весь символ.

1
andrew

Здесь есть несколько хороших ответов, но я хотел бы отметить, что jvm может свободно хранить значение char в пространстве любого размера> = 2 байта.

На многих архитектурах существует штраф за выполнение невыровненного доступа к памяти, поэтому символ может легко быть дополнен до 4 байтов. Изменчивый символ может даже добавляться к размеру строки кэша ЦП, чтобы предотвратить ложное совместное использование. https://en.wikipedia.org/wiki/False_sharing

Для новых Java-программистов может быть не интуитивно понятно, что символьный массив или строка НЕ ​​являются просто несколькими символами. Вы должны учиться и думать о строках и массивах отдельно от «нескольких символов». 

Я также хочу отметить, что символы Java часто используются неправильно. Люди не понимают, что пишут код, который не будет правильно обрабатывать кодовые точки длиной более 16 бит.

1
William Deans

Java выделяет 2 из 2 байтов для символа, как это следует UTF-16. Он занимает минимум 2 байта при сохранении символа и максимум 4 байта. Для символа нет 1 байта или 3 байта памяти.

0
Siva