Unicode
В конце 80-х многие осознали необходимость создания единого стандарта на кодирование символов, что и привело к появлению Unicode.
Unicode - это попытка раз и навсегда зафиксировать конкретное число за конкретным символом.
Понятно, что в 256 символов тут не уложишься при всём желании.
Довольно долгое время казалось, что уж 2-х то байт (65536 символов) должно хватить.
Ан нет - последняя версия стандарта
Unicode - 3.1 определяет уже 94140 символов.
Для такого количества символов, наверное, уже придётся использовать 4 байта (4294967296 символов).
Может быть и хватит на некоторое время... :-)
В набор символов Unicode входят всевозможные буквы со всякими чёрточками и припендюльками, греческие, математические, иероглифы, символы псевдографики и пр. и пр.
В том числе и так любимые нами символы кириллицы (диапазон значений 0x0400-0x04ff).
Так что с этой стороны никакой дискриминации нет.
Если Вам интересны конкретные кода символов, для их просмотра удобно использовать программу "Таблица символов" из WinNT.
Вот, например, диапазон кириллицы:
Если у Вас другая OS или Вас интересует официальное толкование, то полную раскладку символов (charts) можно найти на официальном сайте
Unicode.
Класс String
В большинстве случаев для представления строк в Java используется объект типа java.lang.String.
Это обычный класс, который внутри себя хранит массив символов (char[]), и который содержит много полезных методов для манипуляции символами.
Самые интересные - это конструкторы, имеющие первым параметром массив байтов (byte[]) и методы getBytes().
При помощи этих методов Вы можете выполнять преобразования из массива байтов в строки и обратно.
Для того, чтобы указать какую кодировку при этом использовать у этих методов есть строковый параметр, который задаёт её имя.
Вот, например, как можно выполнить перекодировку байтов из КОИ-8 в Windows-1251:
//Данные в кодировке КОИ-8
byte[] koi8Data=...;
//Преобразуем из КОИ-8 в Unicode
String string=new String(koi8Data,"KOI8_R");
//Преобразуем из Unicode в Windows-1251
byte[] winData=string.getBytes("Cp1251");
Список 8-ми битовых кодировок, доступных в современных JDK и поддерживающих русские буквы Вы можете найти ниже, в разделе "
8-ми битовые кодировки русских букв".
Так как кодировка - это формат данных для символов, кроме знакомых 8-ми битовых кодировок в Java также на равных присутствуют и многобайтовые кодировки.
К таким относятся UTF-8, UTF-16, Unicode и пр.
Например вот так можно получить байты в формате UnicodeLittleUnmarked (16-ти битовое кодирование Unicode, младший байт первый, без признака порядка байтов):
//Строка Unicode
String string="...";
//Преобразуем из Unicode в UnicodeLittleUnmarked
byte[] data=string.getBytes("UnicodeLittleUnmarked");
При подобных преобразованиях легко ошибиться - если кодировка байтовых данных не соответствуют указанному параметру при преобразовании из byte в char, то перекодирование будет выполнено неправильно.
Иногда после этого можно вытащить правильные символы, но чаще всего часть данных будет безвозвратно потеряна.
В реальной программе явно указывать кодовую страницу не всегда удобно (хотя более надёжно).
Для этого была введена кодировка по умолчанию.
По умолчанию она зависит от системы и её настроек (для русских виндов принята кодировка Cp1251), и в старых JDK её можно изменить установкой системного свойства file.encoding.
В JDK 1.3 изменение этой настройки иногда срабатывает, иногда - нет.
Вызвано это следующим: первоначально file.encoding ставится по региональным настройкам компьютера.
Ссылка на кодировку по умолчанию запоминается в нутрях при первом преобразовании.
При этом используется file.encoding, но это преобразование происходит ещё до использования аргументов запуска JVM (собсно, при их разборе).
Вообще-то, как утверждают в Sun, это свойство отражает системную кодировку, и она не должна изменяться в командной строке (см., например, комментарии к BugID
4163515).
Тем не менее в JDK 1.4 Beta 2 смена этой настройки опять начала оказывать эффект.
Что это, сознательное изменение или побочный эффект, который может опять исчезнуть - Sun-овцы ясного ответа пока не дали.
Эта кодировка используется тогда, когда явно не указанно название страницы.
Об этом надо всегда помнить - Java не будет пытаться предсказать кодировку байтов, которые Вы передаёте для создания строки String (так же она не сможет прочитать Ваши мысли по этому поводу :-).
Она просто использует текущую кодировку по умолчанию.
Т.к. эта настройка одна на все преобразования, иногда можно наткнуться на неприятности.
Для преобразования из байтов в символы и обратно следует пользоваться только этими методами.
Простое приведение типа использовать в большинстве случаев нельзя - кодировка символов при этом не будет учитываться.
Например, одной из самых распространённых ошибок является чтение данных побайтно при помощи метода read() из InputStream, а затем приведение полученного значения к типу char:
InputStream is=...;
int b;
StringBuffer sb=new StringBuffer();
while((b=is.read())!=-1){
sb.append((char)b); // так делать нельзя
}
String s=sb.toString();
Обратите внимание на приведение типа - "(char)b".
Значения байтов вместо перекодирования просто скопируются в char (диапазон значений 0-0xFF, а не тот, где находится кириллица).
Такому копированию соответствует кодировка ISO-8859-1 (которая один в один соответствует первым 256 значениям Unicode), а значит, можно считать, что этот код просто использует её (вместо той, в которой реально закодированы символы в оригинальных данных).
Если Вы попытаетесь отобразить полученное значение - на экране будут или вопросики или кракозяблы.
Например, при чтении строки "АБВ" в виндовой кодировке может запросто отобразиться что-то вроде такого: ""ÀÁÂ".
Подобного рода код часто пишут программисты на западе - с английскими буквами работает, и ладно.
Исправить такой код легко - надо просто заменить StringBuffer на ByteArrayOutputStream:
InputStream is=...;
int b;
ByteArrayOutputStream baos=new ByteArrayOutputStream();
while((b=is.read())!=-1){
baos.write(b);
}
//Перекодирование байтов в строку с использованием
//кодировки по умолчанию
String s=baos.toString();
//Если нужна конкретная кодировка - просто укажите
//её при вызове toString():
//
//s=baos.toString("Cp1251");
Более подробно о распространённых ошибках смотрите раздел "
Типичные ошибки".