Тип данных char
Символы описываются в языке Java char типом. Символы преобразуются по таблице кодировки UTF-16. По большому счёту это все буквы, числа и специальные символы существующие на нашей планете.
Размер в байтах — 2 байта
Возможные значения (от..до) — 0..65,535
Значение по умолчанию — ‘\u0000’
Пример объявление символьных типов:
char c1 = 'a';
Тип char является псевдоцелочисленным типом, поэтому значения этого типа можно задавать в виде числа — кода символа из таблицы кодировки UTF-16. Каждому символу соответствует определённое число из таблицы и Java при виде этого числа в рамках типа char выводит его на экран как символ.
Например, при выполнении этого кода
char c2 = 97; System.out.println(c2);
на консоль выведется
Презентацию с видео можно скачать на Patreon .
- Пробелы
- Идентификаторы
- Правила именования переменных
- Комментарии
- Разделители
- Ключевые слова
- Примитивные типы данных
- Типы byte, short, int, long
- Числа с плавающей точкой
- Тип данных boolean
- Литералы
- Методы
- Переменные
- Прямой код и дополнительный код
- Преобразование и приведение примитивных типов
- Ввод с клавиатуры
- Задания
В какой кодировке хранятся символы в переменной типа char java
Как уже говорилось ранее, Java – объектно-ориентированный язык. В Java есть классы (class), и есть объекты (object) – экземпляры заданного класса. Однако, Java не является идеальным объектно-ориентированным языком. Почему?
Давайте рассмотрим, как должен выглядеть идеальный объектно-ориентированный язык. Если бы Java была таковым, то все типы в ней были бы классами, все переменные – объектами, все действия с переменными – функциями. Например, тип целых чисел был бы неким классом, а все действия с целыми числами – методами этого класса. Описать это пришлось бы следующим образом:
public class Int < public void increment() < . >public void add(Int n) < . >. >
И, если мы хотим, к примеру, увеличить значение переменной n на 1 , то вместо привычного
int n = 0; n++;
необходимо было бы писать так:
Int n = new Int(); n.increment();
Таким образом, в идеальном объектно-ориентированном языке не должно быть никаких плюсов и прочих операций – их необходимо описывать как методы класса. Не должно быть даже присваивания. И, соответственно, не должно быть никаких типов кроме классов. И вообще, в таком случае при создании объекта (например, «целого числа»), создавалась бы некоторая «коробочка», в которую помещалось бы наше некоторое значение, и каждая операция требовала бы «залезания» в эту «коробочку», поиска в ней нашего числа и уже потом произведения с ним определенного действия. Это занимало бы кучу времени. Но Java не является идеальным объектно-ориентированным языком, поэтому мы избежим всех этих неудобств.
Примитивные типы в Java
В Java существует 8 типов, кроме классов:
| boolean | логический тип |
| char | символьный тип |
| byte | целочисленные типы |
| short | |
| int | |
| long | |
| float | типы с плавающей точкой |
| double |
Рассмотрим их подробнее.
- boolean Это логический тип. Переменные этого типа могут принимать только два значения: true – истина и false – ложь. Памяти на переменную такого типа требуется 1 бит. С переменными этого типа можно производить следующие операции:
операция обозначение присваивание a = true; отрицание !b and (логическое “и”) a && b
a & bor (логическое “или”) a || b
a | bxor (исключающее “или”) a ^ b Как видно из таблицы, у операций and и or по два вида обозначения. В чем разница? Рассмотрим логическое выражение: a && b оно будет вычисляться следующим образом. Если а – истинно, то проверяется условие b , если а ложно, то b не проверяется, а значением выражения автоматически становится ложь. Если же мы напишем: a & b то будут проверяться в любом случае оба выражения. Аналогичная ситуация с операцией «или».
- char Символьный тип данных. Переменная такого типа занимает 2 байта памяти, т.к. хранится в кодировке unicode . С переменными этого типа можно производить только операции присваивания, но зато различными способами. Самый простой из них выглядит так: c = ‘b’; Символ можно представить также в виде его кода, записанного в восьмиричной системе счисления: c = ‘\077’; Где 077 – это обязательно трехзначное число, не большее чем 377 ( =255 в десятичной системе счисления) Или же в 16-ричной системе счисления следующим образом: c = ‘\u12a4’; Кроме того, существуют специальные символы, такие как знак абзаца, разрыв страницы и др. Знак абзаца запишется, например, так: c = ‘\n’; Не будем перечислять их здесь. При необходимости всегда можно заглянуть в справочник.
- byte, short, int, long Целочисленные типы. Они отличаются только максимальной длиной и, соответственно, размером занимаемой памяти.
тип размер диапазон значений byte 1 байт -2 7 … 2 7 -1 short 2 байта -2 15 …2 15 -1 int 4 байта -2 31 …2 31 -1 long 8 байт -2 63 …2 63 -1 Для переменных этих типов определены следующие арифметические операции:
операция обозначение сложение a + b вычитание a — b умножение a * b целочисленное деление a / b взятие остатка a % b инкремент a++
++aдекремент a—
—aУвеличить a на b a += b Увеличить a в b раз a *= b Уменьшить a на b a -= b Уменьшить a в b раз a /= b Как видно из таблицы, у операций инкремента и декремента по два вида обозначения. В чем разница? Если мы напишем: a = b++; то вначале переменной а будет присвоено значение переменной b , а затем значение переменной b будет увеличено на единицу. Если же мы напишем: a = ++b; то сначала b увеличится на единицу, а затем это новое (увеличенное) значение будет присвоено переменной а . Аналогичная ситуация с операцией декремента. Кроме того, для переменных типа int и long определены побитовые логические операции:
операция обозначение and (побитовое “и”) a & b or (побитовое “или”) a | b xor (побитовое исключающее “или”) a ^ b побитовое отрицание ~a сдвиг на 1 бит влево a сдвиг на 1 бит вправо a >> 1
a >>> 1Побитовые логические операции могут также быть применены к переменным типа byte и short, но в этом случае переменная такого типа будет неявно приведена к типу int, и только после этого к ней будет применена логическая операция. После побитового сдвига влево, в конце всегда появляется 0. А вот на побитовый сдвиг вправо следует обратить внимание. Как в памяти хранятся числа? Например, число типа int, равное 2 31 -1 запишется в виде: 011..1 (ноль и тридцать одна единица) Нолик в начале означает, что число положительное. Если же мы хотим записать отрицательное число, то в начале будет стоять единица. Поэтому, когда мы выполняем побитовый сдвиг вправо, то, если число было положительным, вначале остается 0, если же отрицательным, то вначале появляется 1.. Но если по какой-то причине мы все же хотим, чтобы вначале в любом случае появлялся 0, то побитовый сдвиг вправо надо выполнить следующим образом: a >>> b; Для сравнения можно привести следующие примеры:
231-1 >> 1 = 230-1 -1 >> 1 = -1 231-1 >>> 1 = 230-1 -1 >>> 1 = 231-1
Float.MIN_VALUE; Float.MAX_VALUE; Double.MIN_VALUE; Double.MAX_VALUE;
Кроме того, как и у целочисленного типа long , если мы хотим указать, что константа типа именно float , то на конце следует поставить букву f (или F):
1.0f 0.005F
Операции сравнения
Для всех типов, кроме boolean , определены операции сравнения:
| операция | обозначение |
| равенство | == |
| неравенство | != |
| больше | > |
| меньше | |
| больше или равно | >= |
| меньше или равно |
Для типа boolean можно выполнять проверку на равенство/неравенство.
Особенностью типов float и double является значение NaN . NaN никогда не равно самому себе и ничему другому. Для проверки, является ли значением переменной (типа float/double ) NaN , существуют специальные функции:
float f; double d; . Float.isNaN(f); Double.isNaN(d);
Преобразование типов
Иногда возникают ситуации, когда необходимо переменной одного типа присвоить значение переменной другого типа. Например:
int a = 1; byte b = 2; a = b;
Как поступать в этом случае? Все типы условно можно расположить «в порядке увеличения»:
Если мы хотим переменой «большего» типа присвоить значение «меньшего» типа, то выполняем обычное присваивание:
int a = 1; float f = 2.2f; f = a;
Если же наоборот, переменной «меньшего» типа значение «большего», то надо указывать тип, в который мы преобразовываем:
int a = 1; float f = 2.2f; a = (int)f;
При этом дробная часть просто отбросится.
Преобразовывать число в переменную типа char всегда необходимо явно, а вот переменную типа char явно преобразовывают только в byte и short :
int a; char c = '*', c1; byte b; a = c; c1 = (char)a; b = (byte)c1;
Небольшое отступление о кодировке Unicode
Как уже говорилось, переменные типа char в Java хранятся в кодировке Unicode. Еще недавно казалось, что любой символ помещается в 7 бит, т.е. для хранения одного символа достаточно 1 байта. Однако, в некоторых алфавитах символов больше, чем 256. Идея Unicode состоит в том, чтобы хранить 1 символ четырьмя байтами. Т.е. в такой кодировке помещается 2 32 , что больше 4 млрд. символов.
Существуют кодировки символов с постоянной длиной: UCS–2 (двухбайтовая кодировка) и UCS–4 (четырехбайтовая кодировка). В кодировке UCS–4 символ записывается, как есть, согласно стандарту Unicode. На самом деле в таблице Unicode количество всех символов меньше 2 16 , и для записи символа в кодировке UCS–2 , берётся его запись, согласно стандарту Unicode, и из неё выкидываются первые два байта. Также существует кодировка UTF–8 , в которой разные символы записываются разным количеством байт. Наиболее часто встречающиеся – 1 байтом, менее встречающиеся – 2 байтами и совсем редко встречающиеся – 3 байтами.
Символ с номером, меньшим чем 128 записывается так:
Символ с номером большим, чем 128, но меньшим, чем 2048 – так:
| 110. | 10. |
Символ с номером между 2048 и 65536 – так:
| 1110. | 10. | 10. |
В данный момент любой символ в UTF-8 записывается не более чем 3 байтами.
В какой кодировке хранятся символы в переменной типа char java
Одной из основных особенностей Java является то, что данный язык является строго типизированным. А это значит, что каждая переменная и константа представляет определенный тип и данный тип строго определен. Тип данных определяет диапазон значений, которые может хранить переменная или константа.
Итак, рассмотрим систему встроенных базовых типов данных, которая используется для создания переменных в Java. А она представлена следующими типами.
-
boolean : хранит значение true или false
boolean isActive = false; boolean isAlive = true;
byte a = 3; byte b = 8;
short a = 3; short b = 8;
int a = 4; int b = 9;
long a = 5; long b = 10;
double x = 8.5; double y = 2.7;
float x = 8.5F; float y = 2.7F;
При этом переменная может принимать только те значения, которые соответствуют ее типу. Если переменная представляет целочисленный тип, то она не может хранить дробные числа.
Целые числа
Все целочисленные литералы, например, числа 10, 4, -5, воспринимаются как значения типа int , однако мы можем присваивать целочисленные литералы другим целочисленным типам: byte , long , short . В этом случае Java автоматически осуществляет соответствующие преобразования:
byte a = 1; short b = 2; long c = 2121;
Однако если мы захотим присвоить переменной типа long очень большое число, которое выходит за пределы допустимых значений для типа int, то мы столкнемся с ошибкой во время компиляции:
long num = 2147483649;
Здесь число 2147483649 является допустимым для типа long, но выходит за предельные значения для типа int. И так как все целочисленные значения по умолчанию расцениваются как значения типа int, то компилятор укажет нам на ошибку. Чтобы решить проблему, надо добавить к числу суффикс l или L , который указывает, что число представляет тип long:
long num = 2147483649L;
Как правило, значения для целочисленных переменных задаются в десятичной системе счисления, однако мы можем применять и другие системы счисления. Например:
int num111 = 0x6F; // 16-теричная система, число 111 int num8 = 010; // 8-ричная система, число 8 int num13 = 0b1101; // 2-ичная система, число 13
Для задания шестнадцатеричного значения после символов 0x указывается число в шестнадцатеричном формате. Таким же образом восьмеричное значение указывается после символа 0 , а двоичное значение — после символов 0b .
Также целые числа поддерживают разделение разрядов числа с помощью знака подчеркивания:
int x = 123_456; int y = 234_567__789; System.out.println(x); // 123456 System.out.println(y); // 234567789
Числа с плавающей точкой
При присвоении переменной типа float дробного литерала с плавающей точкой, например, 3.1, 4.5 и т.д., Java автоматически рассматривает этот литерал как значение типа double . И чтобы указать, что данное значение должно рассматриваться как float , нам надо использовать суффикс f:
float fl = 30.6f; double db = 30.6;
И хотя в данном случае обе переменных имеют практически одно значения, но эти значения будут по-разному рассматриваться и будут занимать разное место в памяти.
Символы и строки
В качестве значения переменная символьного типа получает одиночный символ, заключенный в одинарные кавычки: char ch=’e’; . Кроме того, переменной символьного типа также можно присвоить целочисленное значение от 0 до 65535 . В этом случае переменная опять же будет хранить символ, а целочисленное значение будет указывать на номер символа в таблице символов Unicode (UTF-16). Например:
char ch=102; // символ 'f' System.out.println(ch);
Еще одной формой задания символьных переменных является шестнадцатеричная форма: переменная получает значение в шестнадцатеричной форме, которое следует после символов «\u». Например, char ch=’\u0066′; опять же будет хранить символ ‘f’.
Символьные переменные не стоит путать со строковыми, ‘a’ не идентично «a». Строковые переменные представляют объект String , который в отличие от char или int не является примитивным типом в Java:
String hello = "Hello. "; System.out.println(hello);
Кроме собственно символов, которые представляют буквы, цифры, знаки препинания, прочие символы, есть специальные наборы символов, которые называют управляющими последовательностями. Например, самая популярная последовательность — «\n». Она выполняет перенос на следующую строку. Например:
String text = "Hello \nworld"; System.out.println(text);
Результат выполнения данного кода:
Hello world
В данном случае последовательность \n будет сигналом, что необходимо сделать перевод на следующую строку.
Начиная с версии 15 Java поддерживает тестовые блоки (text blocks) — многострочный текст, облеченный в тройные кавычки. Рассмотрим, в чем их практическая польза. Например, выведем большой многострочный текст:
String text = "Вот мысль, которой весь я предан,\n"+ "Итог всего, что ум скопил.\n"+ "Лишь тот, кем бой за жизнь изведан,\n"+ "Жизнь и свободу заслужил."; System.out.println(text);
С помощью операции + мы можем присоединить к одному тексту другой, причем продолжение текста может располагаться на следующей строке. Чтобы при выводе текста происходил перенос на следующую строку, применяется последовательность \n.
Результат выполнения данного кода:
Вот мысль, которой весь я предан, Итог всего, что ум скопил. Лишь тот, кем бой за жизнь изведан, Жизнь и свободу заслужил.
Текстовые блоки, которые появились в JDK15, позволяют упростить написание многострочного текста:
String text = """ Вот мысль, которой весь я предан, Итог всего, что ум скопил. Лишь тот, кем бой за жизнь изведан, Жизнь и свободу заслужил. """; System.out.println(text);
Весь текстовый блок оборачивается в тройные кавычки, при этом не надо использовать соединение строк или последовательность \n для их переноса. Результат выполнения программы будет тем же, что и в примере выше.
Pro Java
Хоть тип char и относится к целочисленным типам, но все же он стоит несколько особнячком, так как предназначен для представления отдельных символов Unicode. Поэтому его рассмотрим отдельно от целочисленных типов, хотя над ним можно совершать все те же самые операции, что и над целочисленными типами (сложение, вычитание и т.д. и т.п.). Но в тоже время им можно задавать значения при помощи символьных литералов, например ‘A’ – то есть любым символом заключенным в одинарные кавычки , но не стоит это путать со строкой “А”, состоящей из одного символа.
Как уже упоминалось размер этого типа равен 16 битам и поэтому может содержать значения от 0 до 65535 в десятичном исчислении. Отрицательных значений для типа char не существует . Это единственное без знаковый целочисленный тип данных в Java.
Задавать значения типа char можно при помощи следующих литералов или управляющих символов, например:
Символьные литералы
‘A’ – символьный литерал, заданный напрямую любым отображаемым символом Unicode
‘\uxxxx’ – символ Unicode, где xxxx цифровой код символа Unicode в шестнадцатеричной форме
‘\xxx’ – символ кодовой таблицы Latin-1, где xxx восьмеричный код символа Latin-1
1046 – код символа Unicode в десятичном исчислении
0x0950 – код символа Unicode в шестнадцатеричном формате
Поскольку char – это целочисленный тип, то ему можно присваивать значения всеми теми же литералами, что и другим целочисленным, это могут быть и двоичные и восьмеричные литералы, только в этом нет ни какого смысла и это даже не удобно.
Управляющие символы (так же должны быть заключены в одинарные кавычки):
\b – backspase BS – забой (\u0008 в кодировке Unicode и 8 в десятичной)
\t – horizontal tab HT – табуляция (\u0009 в кодировке Unicode и 9 в десятичной)
\n – line feed LF – конец строки (\u000a в кодировке Unicode и 10 в десятичной)
\f – form feed FF – конец страницы (\u000с в кодировке Unicode и 12 в десятичной)
\r – carriage return CR – возврат каретки (\u000d в кодировке Unicode и 13 в десятичной)
\” – двойная кавычка (\u0022 в кодировке Unicode и 34 в десятичной)
\’ – одинарная кавычка (\u0027 в кодировке Unicode и 39 в десятичной)
\\ – backslash \ – обратная косая черта (\u005c в кодировке Unicode и 92 в десятичной)
Для справки про запись символов в восьмеричной системе счисления: код любого символа с десятичной кодировкой от 0 до 255 можно задать, записав его не более чем тремя цифрами в восьмеричной системе счисления в апострофах после обратной наклонной черты: ‘ \123’ — буква S, ‘ \346’ — буква Ж в кодировке CP1251. Особого смысла нет использовать эту форму записи для печатных и управляющих символов, перечисленных в предыдущем пункте, поскольку компилятор сразу же переведет восьмеричную запись в шестнадцатеричную. Наибольший восьмеричный код
‘ \377’ — десятичное число 255.
ПРИМЕЧАНИЕ
Прописные русские буквы в кодировке Unicode занимают диапазон от ‘\u0410’ — заглавная буква А, до ‘\u042F’ — заглавная Я, строчные буквы от ‘\u0430’ — а, до ‘\u044F’ — я.
Из этого ряда выпала только буква Ё. Ну ё маё Но все же она представлена в Unicode.
Заглавная Ё – ‘\u0401’, и строчная ё – ‘\u0451’.
Ну а теперь немножко попрактикуемся, чтобы не было скучно, и продолжим, так как это еще не все с типом char.
Как видно из скрина программы, значения переменным типа char можно задавать разными способами, как через десятичный код символа, так и через шестнадцатеричный, а для управляющих символов доступны кроме кодов еще и сами управляющие символы.
Ради прикола я создал переменную с идентификатором ё, который вполне допустив в Java, так как Java использует символы Unicode даже для записи кода самой программы.
Вывод программы в консоли Eclipse такой:
![]()
Как видим отработали наши символы табуляции, которые мы использовали, а так же оператор print(), который печатает без перевода на новую строку. Кроме того фразу Hello World мы заключили в двойные кавычки и немного ее разбили символом перевода строки и двумя символами табуляции.
Затем, в строке 22, мы увеличили значение переменной ё на единицу и снова вывели результат.
Таким образом видно, что примитивный тип char это целочисленный тип, над которым возможны все те же самые операции, что и над другими целочисленными типами.
В Eclipse эта программа запускается нормально, а вот в консоли это уже совсем другой кордебалет.
![]()
Ну что? Потанцуем?
Прежде чем запускать эту программу, во первых надо задать для консоли кодировку UTF8, а затем запускать саму программу следующей командой:
java -Dfile.encoding=UTF-8 CharType
Это необходимо делать, так как при выводе на консоль виртуальная машина java делает обратное преобразование из кодировки UTF8 в кодировку операционной системы, для Windows это 1251 или 866 в консоли.
CharType – это не параметр, это программа так называется, вернее класс.
Надо отметить, что если у вас нет каких-то специальных символов и вы просто используете русский язык под Windows, то все эти танцы с бубнами не нужны. Они так же не нужны если вы пишете под Mac OS X на Java, поскольку консоль там нативно поддерживает Unicode.
Стоит так же упомянуть, что на нынешний момент количество символов Unicode уже превышает 65536, поэтому с Java 5 для работы с этими символами было введено понятие суррогатной пары, поскольку 16 разрядного типа char уже стало не хватать. Для работы с этими символами используется две переменные типа char. Первый символ в паре обозначающих один символ Unicode называется high surrogate, а второй – low surrogate, а вместе они называются суррогатной парой и их обоих так же можно хранить в переменной типа int.
На практике, использование суррогатной пары, встречается чрезвычайно редко, но знать об этом следует. Более подробно об Unicode в Java и кодовых точках можно почитать тут и тут. И еще тут.
![]()
Приведу простой пример по работе с суррогатной парой в Java, чтобы было хоть какое-то представление. В примере, естественно, есть вещи которые еще мы не проходили, такие как циклы, массивы, условные проверки и т.п., но надеюсь что все будет понятно.
Данная программа проверяет является ли суррогатная пара допустимым значением и если да, то выводит этот символ на экран, а так же выводит код кодовой точки.
В данном случае выводится символ ракеты представленной кодом UTF-16BE 0xD83D и 0xDE80, что соответствует кодовой точке 128640.
Как видно в примере переменным типа char значения заданы при помощи шестнадцатеричных цифровых литералов.
![]()
Символ ракеты в консоли Eclipse и Windows выводится достаточно убого, но все же его можно узнать .
Так же следует обратить внимание на то что я подсветил желтым
![]()
Ну а теперь посмотрим на вывод этой программы в консоли Eclipse
![]()
И в консоли Windows
![]()
![]()
В принципе ракету можно узнать в этом символе . Сразу же хочу отметить, что консоли Eclipse и Windows могут отобразить далеко не все дополнительные символы Unicode.
На этом с char пока все. И еще пара ссылок по теме Unicode тут и тут.
