Чем отличаются кодировки?
Продолжаем тему прошлой недели и снова поговорим о классе String. В java 9 вышло интересное обновление - компактные строки. Чтобы лучше понять, в чём была проблема и как она решена, разберём в этом посте отличия между кодировками. А в четверг обсудим уже сами компактные строки.
Итак, символы хранятся в памяти в виде чисел. Кодировки отвечают за формат хранения и правила перевода символов в числа и обратно. Кодировки условно делятся на две группы:
🔹 ASCII-based
🔹 Unicode-based
1️⃣ ASCII
В большинстве ASCII кодировок символ занимает 1 байт и содержит число от 0 до 256. Первые 128 значений транслируются одинаково во всех кодировках:
▫️0-31: управляющие последовательности - перенос строки, конец файла и т.д.
▫️32-127: латинский алфавит, цифры, знаки препинания
Значения 128-255 отображаются на специфичные символы языков. Разные кодировки - разные наборы символов:
🔸Кириллица: ISO-8859-5, Windows-1251
🔸Греческий алфавит: ISO-8859-7, Windows-1253
🔸Исландские символы: OEM 861
200 может стать Ш, Θ, È или чем-то ещё. Фраза Я люблю Java в другой кодировке отобразится как Ď ŰîŃŰî Java.
✅ Компактный формат: 1 символ — 1 байт
❌ Всего 256 значений — нет места для эмодзи
❌ Неоднозначность трактовки
❌ Нельзя использовать украинский и норвежский язык в одном тексте
2️⃣ Unicode
В основе преобразований лежит гигантская таблица с большинством символов, которые используются в мире. Первые 127 символов полностью совпадают с ASCII.
Но ASCII-кодировки не умеют читать символы больше 255. Если подсунуть им юникод, то непонятные значения превратятся в❓ и текст Я люблю Java отобразится как ? ????? Java.
Как хранится юникод.
Ранние версии используют отображение 1 к 1. Все символы хранятся одинаково и занимают одинаковое количество памяти.
Одна из первых кодировок UCS-2 хранила один символ в двух байтах. После ASCII с их диапазоном 0-256 казалось, что диапазона 0-65536 хватит навсегда.
Со временем в таблицу добавилось больше символов и встал вопрос об эффективном хранении данных. Сегодня, чтобы однозначно представить символ юникода нужно 32 бита — так символы хранятся в UTF-32:
✅ Прямое отображение
✅ Простота обработки
✅ Очень много символов
❌ Неэффективный расход памяти — если использовать только латиницу с кодами типа 0..045 и 0...077, три четверти памяти будет занято нулями.
Чтобы решить проблему выше, появились кодировки с переменной длиной: UTF-8 и UTF-16.
Они используют не отображение 1 к 1, а схему с флажками и вычислениями.
В UTF-8 символ занимает 1, 2, 3 или 4 байта. В UTF-16 популярные символы занимают 2 байта, а непопулярные - 4.
✅ Экономный расход памяти для латинских символов
❌ Обработка и поиск происходят чуть медленнее, тк надо делать преобразования
❌ Отметка длины находится в первых 2 битах и уменьшает диапазон значений
Если в структуре 2 или больше байтов, то одни процессоры быстрее считывают их в прямом порядке, а другие — в обратном. Поэтому у UTF-16 и UTF-32 могут быть приставки LE или BE: Little/Big endian.
Что в java. В ранних версиях для char использовалась UCS-2, один символ занимал 2 байта. Затем java перешла на UTF-16 с переменной длиной.
Ну а что с этим не так, и как обстоят дела в java 9 - поговорим в следующем посте.
Продолжаем тему прошлой недели и снова поговорим о классе String. В java 9 вышло интересное обновление - компактные строки. Чтобы лучше понять, в чём была проблема и как она решена, разберём в этом посте отличия между кодировками. А в четверг обсудим уже сами компактные строки.
Итак, символы хранятся в памяти в виде чисел. Кодировки отвечают за формат хранения и правила перевода символов в числа и обратно. Кодировки условно делятся на две группы:
🔹 ASCII-based
🔹 Unicode-based
1️⃣ ASCII
В большинстве ASCII кодировок символ занимает 1 байт и содержит число от 0 до 256. Первые 128 значений транслируются одинаково во всех кодировках:
▫️0-31: управляющие последовательности - перенос строки, конец файла и т.д.
▫️32-127: латинский алфавит, цифры, знаки препинания
Значения 128-255 отображаются на специфичные символы языков. Разные кодировки - разные наборы символов:
🔸Кириллица: ISO-8859-5, Windows-1251
🔸Греческий алфавит: ISO-8859-7, Windows-1253
🔸Исландские символы: OEM 861
200 может стать Ш, Θ, È или чем-то ещё. Фраза Я люблю Java в другой кодировке отобразится как Ď ŰîŃŰî Java.
✅ Компактный формат: 1 символ — 1 байт
❌ Всего 256 значений — нет места для эмодзи
❌ Неоднозначность трактовки
❌ Нельзя использовать украинский и норвежский язык в одном тексте
2️⃣ Unicode
В основе преобразований лежит гигантская таблица с большинством символов, которые используются в мире. Первые 127 символов полностью совпадают с ASCII.
Но ASCII-кодировки не умеют читать символы больше 255. Если подсунуть им юникод, то непонятные значения превратятся в❓ и текст Я люблю Java отобразится как ? ????? Java.
Как хранится юникод.
Ранние версии используют отображение 1 к 1. Все символы хранятся одинаково и занимают одинаковое количество памяти.
Одна из первых кодировок UCS-2 хранила один символ в двух байтах. После ASCII с их диапазоном 0-256 казалось, что диапазона 0-65536 хватит навсегда.
Со временем в таблицу добавилось больше символов и встал вопрос об эффективном хранении данных. Сегодня, чтобы однозначно представить символ юникода нужно 32 бита — так символы хранятся в UTF-32:
✅ Прямое отображение
✅ Простота обработки
✅ Очень много символов
❌ Неэффективный расход памяти — если использовать только латиницу с кодами типа 0..045 и 0...077, три четверти памяти будет занято нулями.
Чтобы решить проблему выше, появились кодировки с переменной длиной: UTF-8 и UTF-16.
Они используют не отображение 1 к 1, а схему с флажками и вычислениями.
В UTF-8 символ занимает 1, 2, 3 или 4 байта. В UTF-16 популярные символы занимают 2 байта, а непопулярные - 4.
✅ Экономный расход памяти для латинских символов
❌ Обработка и поиск происходят чуть медленнее, тк надо делать преобразования
❌ Отметка длины находится в первых 2 битах и уменьшает диапазон значений
Если в структуре 2 или больше байтов, то одни процессоры быстрее считывают их в прямом порядке, а другие — в обратном. Поэтому у UTF-16 и UTF-32 могут быть приставки LE или BE: Little/Big endian.
Что в java. В ранних версиях для char использовалась UCS-2, один символ занимал 2 байта. Затем java перешла на UTF-16 с переменной длиной.
Ну а что с этим не так, и как обстоят дела в java 9 - поговорим в следующем посте.