Разве размер символа в Java не равен 2 байтам? - PullRequest
50 голосов
/ 22 февраля 2011

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

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

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

Ответы [ 7 ]

112 голосов
/ 22 февраля 2011

A 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, содержащий взамен символ замены Юникода).

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

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

13 голосов
/ 22 февраля 2011

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

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

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

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

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

6 голосов
/ 22 февраля 2011

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

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

1 голос
/ 05 февраля 2017

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

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

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

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

1 голос
/ 22 февраля 2011

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

1 голос
/ 22 февраля 2011

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

0 голосов
/ 06 декабря 2018

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...