Подтвердить что ты не робот

Java utf8 encoding - char, типы строк

public class UTF8 {
    public static void main(String[] args){
        String s = "ヨ"; //0xFF6E
        System.out.println(s.getBytes().length);//length of the string
        System.out.println(s.charAt(0));//first character in the string
    }
}

выход:

3
ヨ

Пожалуйста, помогите мне понять это. Попытка понять, как работает кодировка utf8 в java. Согласно определению java doc char char: тип данных char - это один 16-разрядный символ Юникода.

Означает ли это, что char тип в java может поддерживать только те символы unicode, которые могут быть представлены с 2 байтами и не более?

В приведенной выше программе количество байтов, выделенных для этой строки, равно 3, но в третьей строке, которая возвращает первый символ (2 байта в java), может содержать символ длиной 3 байта? действительно запутался здесь?

Любые хорошие ссылки на эту концепцию в java/general были бы действительно оценены.

4b9b3361

Ответ 1

Ничто в вашем примере кода напрямую не использует UTF-8. Строки Java кодируются в памяти с использованием UTF-16. Кодовые страницы Unicode, которые не помещаются в один 16-разрядный char, будут закодированы с использованием пары 2- char, известной как суррогатная пара.

Если вы не передадите значение параметра String.getBytes(), он возвращает массив байтов, который содержит содержимое String, закодированное с использованием базовой кодировки по умолчанию для ОС. Если вы хотите обеспечить кодированный UTF-8 массив, вам нужно вместо этого использовать getBytes("UTF-8").

Вызов String.charAt() возвращает исходный кодированный UTF-16 char только из памяти в строковой памяти.

Итак, в вашем примере символ Unicode хранится в хранилище String в памяти с использованием двух байтов, кодированных UTF-16 (0x6E 0xFF или 0xFF 0x6E в зависимости от endian), но сохраняется в массиве байтов из getBytes() с использованием трех байтов, которые кодируются с использованием любой кодировки по умолчанию для ОС.

В UTF-8 этот символ Юникода также использует 3 байта (0xEF 0xBD 0xAE).

Ответ 2

String.getBytes() возвращает байты, используя кодировку символов по умолчанию платформы, которая не обязательно соответствует внутреннему представлению.

Лучше никогда не использовать этот метод в большинстве случаев, потому что в большинстве случаев не имеет смысла полагаться на кодировку по умолчанию платформы. Вместо этого используйте String.getBytes(String charsetName) и явным образом задайте набор символов, который должен использоваться для кодирования вашей строки в байтах.

Ответ 3

UTF-8 - это кодирование с переменной длиной слова, которое использует только один байт для символов ASCII (значения от 0 до 127) и два, три (или даже больше) байта для других символов Unicode.

Это связано с тем, что старший бит байта используется для указания "это многобайтовая последовательность", поэтому один бит на 8 не используется для фактического представления "реальных" данных (код char), но для отметки байт.

Итак, несмотря на то, что Java использует 2 байта в ram для каждого char, когда символы "сериализуются" с использованием UTF-8, они могут генерировать один, два или три байта в результирующем массиве байтов, как UTF-8 кодирование работает.