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 тут и тут.
Типы
Вселенная Java состоит из трёх субстанций: примитивы, объекты и коты. Про последних в документации ничего не говорится, поэтому их рассматривать не будем, но они существуют!
Примитивные типы Java не являются объектами. К ним относятся:
- boolean — булев тип, может иметь значения true или false
- byte — 8-разрядное целое число
- short — 16-разрядное целое число
- int — 32-разрядное целое число
- long — 64-разрядное целое число
- char — 16-разрядное беззнаковое целое, представляющее собой символ UTF-16 (буквы и цифры)
- float — 32-разрядное число в формате IEEE 754 с плавающей точкой
- double — 64-разрядное число в формате IEEE 754 с плавающей точкой
Примитивный в данном случае не оскорбление, а просто даёт понять, что речь идёт о простом типе, который не умеет прыгать, спать или мяукать. Да что он вообще умеет? Ой, всё.
Простые числовые типы
Тип | Разрядность | MIN | MAX |
---|---|---|---|
byte | 8 бит | -128 | 127 |
short | 16 бит | -32768 | 32767 |
int | 32 бит | -2147483648 | 2147483647 |
long | 64 бит | -9223372036854775808 | 9223372036854775807 |
float | 32 бит | -3.4E+38 | 3.4E+38 |
double | 64 бит | -1.7E+308 | 1.7E+308 |
Целочисленные типы
Java определяет четыре целочисленных типа: byte, short, int, long. Они могут быть положительными и отрицательными (Java не поддерживает только положительные значения без знака, как некоторые языки программирования).
Тип byte
Наименьший по размеру целочисленный тип — byte. Это 8-битовый тип с диапазоном допустимых значений от -128 до 127. Переменные типа byte часто используются при работе с потоком данных из сети или файла, а также при работе с необработанными двоичными данными или в массивах для экономии памяти.
Объявить переменную типа byte можно следующим образом:
byte c, a, t; // объявили сразу три переменные
В арифметических выражениях с переменными типа byte вычисления выполняются как с типом int, т.е. с помощью 32-битовой арифметики, а полученный результат будет 32-битовым. Смотри пример с short.
Строку с числом перевести в данный тип можно через метод parseByte(String):
byte x = Byte.parseByte("100");
Класс Byte является оболочкой для данного типа. Без необходимости не используйте в Android класс Byte.
Слово «байт» (byte) возникло в компании IBM примерно в 1956 году. Оно произошло от слова bite («кусок»), но его было решено писать через букву y, чтобы не путать со словом «bit» («бит»). В течение некоторого времени слово «байт» обозначало просто число битов в конкретном потоке данных. Однако в середине 1960-х, в связи с разработкой семейства компьютеров System/360 в компании IBM, это слово стало обозначать группу из восьми бит.
Любопытно, что bite имеет также значение «укус» (сущ.) или «укусить» (глагол). Таким образом это наш родной «Кусь!»
Тип short
Тип short — 16-битовый тип в диапазоне от -32768 до 32767. Используется очень редко.
short m;
В арифметических выражениях с переменными типа short вычисления выполняются как с типом int, т.е. с помощью 32-битовой арифметики, а полученный результат будет 32-битовым. Например, такой код не пройдёт.
// накорми кота short fishNumber = 3; // три рыбки short beefNumber = 2; // два кусочка говядины short breakfast = 0; breakfast = fishNumber + beefNumber; // завтрак чемпиона
Java будет ругаться на последнюю строчку, так как итоговый результат не может быть short. Как вариант, вам нужно преобразовать результат снова в 16-битовое число.
breakfast = (short) (fishNumber + beefNumber); // завтрак чемпиона
Явно перевести строку с числом в тип short можно через метод parseShort(String):
short x = Short.parseShort("100");
Класс Short является оболочкой для данного типа. Без необходимости не используйте в Android класс Short.
Тип int
Целые числа, представленные типом int, являются самым распространённым типом в программе, с которым вы будете работать. Поэтому нужно хорошенько изучить его и узнать его достоинства и ограничения. Это 32-битовый тип, имеющий диапазон допустимых значений от -2147483648 до 2147483647 (около двух миллиардов). Этого числа вполне достаточно, чтобы посчитать всех котов на свете. Часто используется в циклах, индексировании массивов, хотя может показаться, что для небольших операций в цикле и массивах проще использовать short или byte. Нужно запомнить, что тип int эффективен в этих случаях из-за особенностей структуры вычислительных процессоров. Просто примите на веру.
Сказка про тип int
Зададим себе вопрос, насколько большим может быть целое число типа int?
Напишем простую программу, где будем умножать переменную саму на себя. Для начала присвоим ей значение 2, а дальше строчка за строчкой будем выводить результат. Результаты будем отдавать коту учёному LogCat. Весь код поместим в обработчик события щелчка на кнопке нашей учебной программы, а первую строчку поместим выше её.
final String TAG = "ExpressCourse"; public void onClick(View view)
Запустите программу и нажмите кнопку. В нижней части студии откройте панель Android Monitor и в ней вкладку logcat. Настройте его фильтр, чтобы отображались только наши сообщения. В результате мы получим такую картину:
2 4 16 256 65536 0 0 0 0
Что за бред, скажете вы. Когда мы умножаем 65536 на себя, то получаем 0 (Только не говорите об этом учительнице по математике). А потом, естественно, программа умножает 0 на 0 и продолжает выводить результаты.
Вы ещё больше удивитесь, если в качестве начального значения возьмёте число 3. На этот раз вы сможете получить даже отрицательные значения.
3 9 81 6561 43046721 -501334399 2038349057 -1970898431 120648705
Проверьте самостоятельно. Если вы и это попытаетесь доказать учительнице, то исключение из учебного заведения вам гарантировано.
Деление целочисленных чисел
Запомните, что при делении целочисленных чисел остаток отбрасывается. Поэтому следующие примеры вернут один и тот же результат. Бедная учительница, её увезут в психушку.
6 / 3 = 2 7 / 3 = 2 8 / 3 = 2 9 / 3 = 3
На ноль делить нельзя, увидите ошибку.
Если нужен узнать остаток от деления, то используйте оператор % (оператор деления по модулю).
Log.d(TAG, "Остаток 6 % 3: " + 6 % 3); // 0 Log.d(TAG, "Остаток 7 % 3: " + 7 % 3); // 1 Log.d(TAG, "Остаток 8 % 3: " + 8 % 3); // 2 Log.d(TAG, "Остаток 9 % 3: " + 9 % 3); // 0
Класс Integer является оболочкой для данного типа. Без необходимости не используйте в Android класс Integer. Для сравнения: тип int занимает 4 байт памяти, а Integer — 16 байт.
Также есть специальный класс BigInteger для проведения арифметических действий повышенной точности (финансовые расчёты).
В Java 7 можно использовать знак подчёркивания для удобства. Например, так:
int myInt = 1_000_000; // миллион
Компилятор не обращает внимания на эти знаки, а человеку проще понять, что ему предлагают миллион или миллиард. В Android относительно недавно появилась полноценная поддержка Java 7 и вам в настройках нужно указать новую версию компилятора.
Этот приём относится не только к int, но и к другим типам чисел.
Как сконвертировать строку или CharSequence в int?
String mString = "42"; // строка int mInt = Integer.parseInt(mString);
Если у вас тип CharSequence, то его можно сконвертировать сначала в строку при помощи метода toString(), а потом в int.
Метод parseInt() предпочтительнее метода valueOf():
int number; // плохой вариант number2 = Integer.valueOf("1"); // отличный вариант number = Integer.parseInt("1");
Как сконвертировать число в строку?
Если сложить число и строку, то Java автоматически конвертирует число в строку. Пользуясь этим свойством, программисты часто прибавляют к числу пустую строку. Но лучше использовать метод valueOf():
int number = 1; // плохой вариант String numberString = "" + number; // отличный вариант String numberString = String.valueOf(number);
Добавить ведущие нули
Если мы хотим получить строку из числа, добавим при этом несколько нулей вначале, то поможет метод format(), только учитывайте число цифр в самом числе.
int givenNumber = 777; String formattedNumber = String.format("%06d", givenNumber); System.out.println("Число с ведущими нулями: " + formattedNumber); // Число с ведущими нулями: 000777
Тип long
Тип long — это 64-битный тип со знаком, используемый в тех случаях, когда используется очень большое значение, которое не способен хранить тип int. Например, чтобы вычислить расстояние, которое прошёл солнечный луч от солнца до зеркала, превратившись в солнечного зайчика, за которым безуспешно охотится котёнок, вам понадобится именно этот тип.
Можно использовать символы l или L для обозначения числа типа long. Рекомендую использовать заглавную букву, чтобы избежать возможной путаницы. Например, напишем пример:
// сколько ночей в арабских сказках? long night = 101l; System.out.println(night);
Запустив пример, вы увидите ответ 101. Почему так получилось? А потому что последний символ — это не единица, а символ l. Присмотритесь внимательнее. Если бы мы написали long night = 101L, то не ломали бы голову себе.
Конвертируем строку в данный тип.
long x = Long.parseLong("100");
Класс Long является оболочкой для данного типа. Без необходимости не используйте в Android класс Long.
Типы с плавающей точкой
Числа с плавающей точкой (иногда их называют действительными числами) применяются при вычислении выражений, в которых требуется точность до десятичного знака. Например, это может быть вычисление квадратного корня, значений синуса, косинуса и т.п. Существует два типа с плавающей точкой: float и double, которые представляют числа одинарной и двойной точности.
Слово «плавающая» означает, что десятичная точка может располагаться в любом месте (она «плавает»). Вот коты плавать не особенно любят, поэтому они не float и не double.
Тип float
Тип float определяет значение одинарной точности, которое занимает 32 бит. Переменные данного типа удобны, когда требуется дробная часть без особой точности, например, для денежных сумм.
Рекомендуется добавлять символ F или f для обозначения этого типа, иначе число будет считаться типом double.
float tugrik = 11.6F;
Конвертируем из строки.
float x = Float.parseFloat("19.95");
Класс Float является оболочкой для данного типа. Без необходимости не используйте в Android класс Float.
Также есть специальный класс BigDecimal для проведения арифметических действий повышенной точности (финансовые расчёты).
Тип double
Тип double обеспечивает двойную точность, что видно из его названия (double — двойная). Занимает 64 бит для хранения значений. Многие математические функции возвращают значения типа double. Кстати, современные процессоры оптимизированы под вычисления значений двойной точности, поэтому они предпочтительнее, чем тип float.
double pi, r, a; pi = 3.1416; // приблизительное значение числа π r = 5.5; // радиус окружности a = pi * r * r; // вычисляем площадь окружности
Тип double содержит не только числа, но и слова. Сейчас вам докажу. Разделим число типа double на ноль. Ошибки не произойдёт.
double positive_infinity = 12.0 / 0; System.out.println(positive_infinity);
Пример вернёт значение Infinity (Бесконечность). Если разделить отрицательное число на ноль, то вернётся -Infinity.
А что произойдёт, если сложить две бесконечности? Если рассуждать логически, то сломается интернет, наступит конец света или можно вызвать Волдеморта. Я долго не решался, но потом набрался храбрости и попробовал.
double positive_infinity = 12.0 / 0; double negative_infinity = -15.0 / 0; mInfoTextView.setText(String.valueOf(positive_infinity + negative_infinity));
Вернулось ещё одно слово — NaN. Что это вообще? Может должно вернуться Nyan — ну вы знаете, это странный котик, который летит бесконечно в космосе, оставляя за собой шлейф из радуги.
Умножать две бесконечности я побоялся. И вам не советую.
Класс Double является оболочкой для данного типа. Без необходимости не используйте в Android класс Double.
Конвертация строки в double
Есть несколько вариантов.
// если строка null, то будет исключение NullPointerException // если строка содержит неправильные данные, то будет исключение NumberFormatException String s = "435.23"; Double d = Double.valueOf(s); // возвращает не Double, а double (примитивный тип) // выбрасывает аналогичные исключения double x = Double.parseDouble("19.95"); // В Java 9 признан устаревшим. Не используйте и сейчас String s = "135.360"; Double d = new Double(s); // Через DecimalFormat String s = "135.130"; try < DecimalFormat decimalFormat = new DecimalFormat("#"); double d = decimalFormat.parse(s).doubleValue(); System.out.println("Double value for 135.130 is " + d); >catch (ParseException e)
Конвертация double в строку
При работе с числами double следует держать ухо востро. Рассмотрим пример конвертации трёх чисел.
double number1 = 120; double number2 = 0.033; double number3 = 0.000045158458; System.out.println(String.valueOf(number1)); System.out.println(String.valueOf(number2)); System.out.println(String.valueOf(number3)); /* System.out: 120.0 System.out: 0.033 System.out: 4.5158458E-5 */
Первые два числа нормально преобразовались, а вот третье число преобразовалось в строку в странном виде (на самом деле это научное представление числа). И это может источником проблемы при передаче строки куда-нибудь, например, на сервер. Если сервер не ожидает от вас такой подлости, то будет генерировать ошибки из-за странной записи. Нужно найти другие способы конвертации.
Первый способ — используем String.format().
double number3 = 0.000045158458; System.out.println(String.valueOf(number3)); System.out.println(String.format("%f", number3)); System.out.println(String.format("%.0f", number3)); System.out.println(String.format("%.12f", number3)); /* System.out: 4.5158458E-5 System.out: 0.000045 System.out: 0 System.out: 0.000045158458 */
Последний пример самый подходящий для нас, но вам нужно знать, сколько знаков идёт после десятичной точки. Остальные два пригодятся, если число можно округлить.
Второй способ — метод Double.toString(). У меня метод превратил число в «непонятную» строку. А у некоторых этот пример возвращал строку в нормальном виде. Не заслуживает доверия.
double number3 = 0.000045158458; System.out.println(Double.toString(number3)); /* System.out: 4.5158458E-5 */
Третий способ — добавить пустую строку. В Android не помогло, хотя тоже утверждается, что у кого-то выводится в нормальном виде. Врут, наверное.
double number3 = 0.000045158458; System.out.println(number3 + ""); /* System.out: 4.5158458E-5 */
Четвёртый экзотический способ, которым редко пользуются — DecimalFormat.
double number3 = 0.000045158458; String pattern = "##.############"; DecimalFormat decimalFormat = new DecimalFormat(pattern); System.out.println(decimalFormat.format(number3)); /* System.out: 0.000045158458 */
Символы (тип char)
Для хранения символов Java использует специальный тип char. Он отличается от типа char в языках C/C++, где представляет собой целочисленный тип с размером 8 бит. В Java для char используется кодировка Unicode и для хранения Unicode-символов используется 16 бит или 2 байта. Диапазон допустимых значений — от 0 до 65536 (отрицательных значений не существует).
char ch1, ch2, ch3; ch1 = 67; // код переменной ch2 = 'a'; // сам символ ch3 = 116; // код переменной mInfoTextView.setText("Слово из трёх букв: " + ch1 + ch2 + ch3);
Из примера выше видно, что переменной можно присвоить код символа или непосредственно сам символ, который следует окружить одинарными кавычками. Попробуйте запустить пример и посмотреть, какое слово получится из трёх указанных символов.
Не следует путать символ ‘a’ со строкой «a», состоящей из одного символа. На экране монитора они выглядят одинаково, но в программах ведут себя по разному.
Стандартные символы ASCII можно выводить сразу. Если нужно вывести специальный символ из Unicode, то можно воспользоваться шестнадцатеричным представлением кода в escape-последовательности — вы указываете обратную наклонную черту и четыре цифры после u. Например:
char myChar = '\u0054';
Хотя тип char используется для хранения Unicode-символов, его можно использовать как целочисленный тип, используя сложение или вычитание.
char ch1; ch1 = 'x'; mInfoTextView.append("ch1 содержит " + ch1); ch1++; // увеличим на единицу mInfoTextView.append("ch1 содержит " + ch1);
В результате получим:
ch1 содержит x ch1 содержит y
Если вы думаете, что увеличив значение переменной ch1 ещё на одну единицу, получите символ «й», то глубоко заблуждаетесь.
Чтобы узнать, какой символ содержится в значении переменной, заданной как int, можно воспользоваться двумя специальными методами из класса EncodingUtils:
Для стандартных символов ASCII:
int i = 67; byte[] data = < (byte) i >; CharSequence strSymbol = EncodingUtils.getAsciiString(data); mInfoTextView.setText(strSymbol);
Для расширенной таблицы символов:
int i = 379; byte[] data = < (byte) i >; CharSequence strSymbol = EncodingUtils.getString(data, "windows-1251"); mInfoTextView.setText(strSymbol);
Методы работают со строками, но если мы используем строку из одного символа, то получим то, что нам нужно.
В упрощённом виде, если работаем со стандартными символами ASCII (on 0 до 127), то можно получить символ из int ещё проще.
int ascii = 65; if(ascii > 127)< System.out.println("Wrong value"); >else
Класс Character
Класс Character является оболочкой вокруг типа char. Чтобы получить значение типа char, содержащее в объекте класса Character, вызовите метод charValue().
С классом Character редко имеют дело в Android, но помните, что класс содержит огромное количество констант и методов. Например, можно определить, является ли символ цифрой или буквой, или написан ли символ в нижнем или в верхнем регистре.
Булевы значения
Тип boolean предназначен для хранения логических значений и может принимать только одно из двух возможных значений: true или false. Данный тип всегда возвращается при использовании операторов сравнения (больше, меньше, равно, больше или равно, меньше или равно, не равно). Также он используется в управляющих операторах if и for.
boolean check; check = true;
В отличие от реальной жизни, где вполне может состояться диалог:
- Кать, чай будешь? - Да нет наверное
В компьютерной программе нужно чётко определиться — истина или ложь.
В операторах if используется укороченная запись при значении true:
if (check == true) . // необязательный вариант if (check) . // укороченная запись
Java сам поймёт, что переменную check нужно сравнить с true.
Класс Boolean
Класс Boolean является оболочкой вокруг значений типа boolean. Чтобы получить значение типа boolean из объекта класса Boolean, используйте метод booleanValue(). Тип boolean использует 4 байт памяти, а Boolean — 16. Вывод понятен?
Ещё один совет, применимый ко всем типам. Допустим, нам нужно объявить 32 переменных типа boolean:
boolean mProperty1; boolean mProperty2; . boolean mProperty32;
Умножаем 4 байта на 32 переменных и получаем 128 байт занятой памяти. А если объявим массив:
boolean[] mProperty = new boolean[32]
Считаем: 4 + 8 + 8 + 32 * 1 = 52. С учётом выравнивания памяти по 8 байт, получаем не 52, а 56. Всё равно меньше, чем в первом примере.
Конвертируем строку в булево значение.
Boolean booleanValue = Boolean.valueOf("true"); System.out.println(booleanValue);
Конвертируем булево значение в строку.
boolean boolenValue = true; // первый способ System.out.println(Boolean.toString(booleanValue)); // второй способ System.out.println(String.valueOf(booleanValue));
Приведение типов
Когда мы производим какие-то действия с переменными, то нужно следить за типами. Нельзя умножать котов на футбольные мячи, это противоречит здравому смыслу. Также и с переменными. Если вы присваиваете переменной одного типа значение другого типа, то вспоминайте теорию. Например, вы без проблем можете присвоить значение типа int переменной типа long, так как все числа из диапазона типа int гарантировано помещаются в диапазон чисел long. В этом случае Java выполнит преобразование автоматически, вы даже ничего не заметите.
Представим обратную картину — мы хотим присвоить переменной типа byte значение типа double. Java не сможет автоматически выполнить ваше желание. Не все числа типа double могут стать числом типа byte. Но часть чисел может, например, число 9. В таком случае используется так называемое приведение типов, чтобы подсказать Java о допустимости операции.
Итак, автоматическое преобразование типов осуществляется, если оба типа совместимы и длина целевого типа больше длины исходного типа. В этом случае происходит преобразование с расширением. Вы всегда можете преобразовать любое число типа byte в число типа int. Такая операция произойдёт без вашего участия автоматически.
Таблица выглядит следующим образом.
Сплошные линии обозначают преобразования, выполняемые без потери данных. Штриховые линии говорят о том, что при преобразовании может произойти потеря точности.
Типы целых чисел и чисел с плавающей точкой совместимы частично. Например, число 5 вполне может быть числом с плавающей точкой (5.0).
Совсем не совместимы, например, char и boolean.
С автоматическим приведением мы разобрались. Рассмотрим вариант, когда нужно преобразовать число типа int в число типа byte. Преобразование автоматически невозможно, поскольку byte меньше int. Но, например, число 99 вполне можно использовать и как int и как byte. В этом случае используется явное приведение типов, то есть преобразование из одного типа в другой (преобразование с сужением).
Выглядит это следующим образом:
int a; byte b; // какие-то операции с переменной b = (byte) a;
Как видите, вы в скобках указываете тип, к которому нужно явно привести переменную.
Существует ещё вариант приведения с усечением. Это когда число с плавающей точкой приводится к целочисленному типу. В этом случае отбрасывается дробная часть (хвост). Например, число 3.14 будет усечено до числа 3:
double a = 3.14; byte b = (byte) a;
Если размер целочисленной части слишком велик для целочисленного типа, то значение будет уменьшено до результата деления по модулю на диапазон целевого типа.
Например, попробуйте преобразовать число 454.874 в тип byte:
byte b; double d = 454.874; b = (byte) d; infoTextView.append("b равно " + b);
У меня вывелся удивительный результат: b равно -58.
Рассмотрим такой пример. Допустим у нас есть выражение, где промежуточное значение может выходить за пределы допустимого диапазона:
byte a = 44; byte b = 55; byte c = 101; int d = a * b - c;
При умножении переменных a * b промежуточный результат вышел за пределы диапазона допустимых значений для типов byte. Java во время вычисления промежуточных результатов автоматически повышает тип каждого операнда до int и ошибки не происходит.
Это удобно, но может поставить в тупик в следующем примере:
byte b = 50; b = b * 2;
С виду всё правильно. Если не слишком больше число типа byte, а итоговый результат тоже не выходит за диапазон допустимых значений. Но Java не позволит вам написать подобный код. Происходит следующее. Во время вычисления выражения тип операндов был автоматически повышен до int, как об этом говорилось выше. При этом тип результата тоже был повышен до int. Получается, что результат вычисления равен типу int, а мы пытаемся его присвоить переменной b, которая у нас объявлена как byte. И это несмотря на то, что итоговый результат может быть типом byte. Как же выйти из этого положения? Следует использовать явное приведение типов:
byte b = 50; b = (byte) (b * 2);
Мы рассмотрели единичные примеры. Пора обобщить и запомнить несколько правил.
Типы всех значений byte, short, char повышаются до типа int, как это было рассмотрено выше.
Если один операнд имеет тип long, то тип всего выражения повышается до long.
Если один операнд имеет тип float, то тип всего выражения повышается до float.
Если один операнд имеет тип double, то тип всего выражения повышается до double.
byte b = 45; char c = 'c'; short s = 1005; int i = 700000; float f = 4.55f; double d = 1.456; double result = (f * b) + (i / c) - (d * s); mInfoTextView.append("d равно " + d);
В первом промежуточном выражении (f * b) тип переменной b повышается до float и промежуточный результат также становится float. В следующем выражении (i / c) тип у переменной c повышается до int и промежуточный результат также становится типом int. В выражении (d * s) тип переменной s повышается до double и промежуточное выражение также становится double. В результате у нас появились три промежуточные значения типов: float, int, double. При сложении float и int мы получаем float, затем при вычитании с использованием float и double тип повышается до double, который и становится окончательным типом результата выражения.
Баг или фича в Java: Вывод кириллических символов в консоль
Есть много особенностей, про которые желательно знать, программируя на Java, даже если Вы начинающий программист. Под катом я расскажу как вывести кириллические символы в консоль Windows и наглядно это продемонстрирую.
Начнем с простого.
Базовые типы
- boolean;
- byte, char, short, int, long;
- float, double.
Char — это символьный тип данных. Переменная такого типа занимает 2 байта памяти, так как хранится в кодировке unicode.
С переменными этого типа можно производить только операции присваивания, но зато различными способами. Самый простой из них выглядит так:
c = ‘b’;
Символ можно представить также в виде его кода, записанного в восьмеричной системе счисления:
c = ‘\077’;
Где 077 – это обязательно трехзначное число, не большее чем 377 (=255 в десятичной системе счисления).
Или же в шестнадцатеричной системе счисления следующим образом:
c = ‘\u12a4’;
Кроме того, существуют специальные символы, такие как знак абзаца, разрыв страницы и др. Знак абзаца запишется, например, так:
c = ‘\n’;
Не нужно перечислять их здесь. При необходимости всегда можно заглянуть в справочник.
Теперь внимание. Кодировкой по-умолчанию среды программирования Java является Latin-1. Однако, при выводе в поток System.out символы преобразуются в кодировку по умолчанию для операционной системы. Так для русскоязычной локализации кодировкой по-умолчанию является Windows-1251, для linux таковой будет UTF-8. Однако по задумке Microsoft решили для консоли Windows использовать кодировку Cp866.
Соответственно вывод: для корректного отображения кириллических символов в консоли нужно выводить символы в кодировке Cp866!
Это можно сделать следующим способом:
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
public class Hello <
public static void main(String[] args) throws UnsupportedEncodingException < /*Может возникнуть исключение типа UnsupportedEncodingException*/
String x = «Привет, мир. «; //Это строка, которую мы будем выводить на экран
PrintStream printStream = new PrintStream(System.out, true, «cp866»);
/*Создаем новый поток вывода, который будет автоматически преобразоввывать символы в кодировку Cp866*/
printStream.println(x);
>
>
Сохраним полученный код в файл Hello.java. Далее создадим Hello.bat файл следующего содержания:
javac Hello.java
java -cp . Hello
pause
И поместим его в одну папку с файлом Hello.java. Должно получиться примерно так:
Далее запускаем полученный Hello.bat файл и вуаля, у нас образовался файл Hello.class в той же директории а на экран вывелось сообщение «Привет, мир. » в кодировке Cp866.
Для того, чтобы узнать, какая кодировка в данный момент используется в консоли нужно набрать там «chcp». А для того, чтобы поменять кодировку консоли, нужно набрать «chcp » например «chcp 1251». Продемонстрирую использование этой команды:
Замечание: если у Вас не находит команду javac, то заходим (для Windows 7) «Мой компьютер» — «Свойства» — «Дополнительные параметры системы» — «Переменные среды», находим «Системные переменные» и в переменную Path добавляем строку, куда установлена JDK, например «C:\Program Files\Java\jdk1.7.0_25\bin» — по умолчанию.
Очень странные вещи c Java Characters
Знаете ли вы, что следующее является допустимым выражением Java?
\u0069\u006E\u0074 \u0069 \u003D \u0038\u003B
Вы можете попробовать скопировать и вставить его в основной метод любого класса и скомпилировать. Если вы затем добавите следующий оператор
System.out.println(i);
и после компиляции запустите этот класс, код напечатает число 8!
А знаете ли вы, что этот комментарий вместо этого вызывает синтаксическую ошибку во время компиляции?
/* * The file will be generated inside the C:\users\claudio folder */
Тем не менее, комментарии не должны приводить к синтаксическим ошибкам. Фактически, программисты часто комментируют фрагменты кода, чтобы компилятор их игнорировал. так что же происходит?
Для того, чтобы узнать почему это происходит, потратьте несколько минут на небольшой обзор основ Java о примитивном типе char .
Примитивный тип данных char
Как всем известно, char это один из восьми примитивных типов Java. Это позволяет нам хранить по одному символу. Ниже приведен простой пример, в котором значение символа присваивается типу char :
char aCharacter = 'a';
На самом деле этот тип данных используется нечасто, потому что в большинстве случаев программистам нужны последовательности символов и поэтому они предпочитают строки. Каждое буквальное значение символа должно быть заключено между двумя одинарными кавычками, чтобы не путать с двойными кавычками, используемыми для строковых литералов. Объявление строки:
String s = "Java melius semper quam latinam linguam est";
Есть три способа присвоить литералу значение типа char , и все три требуют включения значения в одинарные кавычки:
- используя один печатный символ на клавиатуре (например ‘&’ ).
- используя формат Unicode с шестнадцатеричной нотацией (например, ‘\u0061’ , который эквивалентен десятичному числу 97 и идентифицирует символ ‘a’ ).
- используя специальный escape-символ (например, ‘\n’ который указывает символ перевода строки).
Давайте добавим некоторые детали в следующих трех разделах.
Печатаемые символы клавиатуры
Мы можем назначить любой символ, найденный на нашей клавиатуре, char переменной, при условии, что наши системные настройки поддерживают требуемый символ и что этот символ доступен для печати (например, клавиши «Canc» и «Enter» не печатаются).
В любом случае литерал, присваиваемый примитивному типу char , всегда заключен между двумя одинарными кавычками. Вот некоторые примеры:
char aUppercase = 'A'; char minus = '-'; char at = '@';
Тип данных char хранится в 2 байтах (16 бит), а диапазон состоит только из положительных чисел от 0 до 65 535. Фактически, существует «отображение», которое связывает определенный символ с каждым числом. Это отображение (или кодирование) определяется стандартом Unicode (более подробно описанным в следующем разделе).
Формат Unicode (шестнадцатеричное представление)
Мы сказали, что примитивный тип char хранится в 16 битах и может определять до 65 536 различных символов. Кодирование Unicode занимается стандартизацией всех символов (а также символов, смайликов, идеограмм и т. д.), существующих на этой планете. Unicode — это расширение кодировки, известной как UTF-8, которая, в свою очередь, основана на старом 8-битном расширенном стандарте ASCII, который, в свою очередь, содержит самый старый стандарт, ASCII code (аббревиатура от American Standard Code for Information Interchange).
Мы можем напрямую присвоить Unicode char значение в шестнадцатеричном формате, используя 4 цифры, которые однозначно идентифицируют данный символ, добавляя к нему префикс \u (всегда в нижнем регистре). Например:
char phiCharacter = '\u03A6'; // Capital Greek letter Φ char nonIdentifiedUnicodeCharacter = '\uABC8';
В данном случае мы говорим о литерале в формате Unicode (или литерале в шестнадцатеричном формате). Фактически, при использовании 4 цифр в шестнадцатеричном формате охватывается ровно 65 536 символов.
Java 15 поддерживает Unicode версии 13.0, которая содержит намного больше символов, чем 65 536 символов. Сегодня стандарт Unicode сильно изменился и теперь позволяет нам представлять потенциально более миллиона символов, хотя уже присвоено только 143 859 чисел конкретным символам. Но стандарт постоянно развивается. В любом случае, для присвоения значений Unicode, выходящих за пределы 16-битного диапазона типа char , мы обычно используем классы вроде String и Character , но поскольку это очень редкий случай и не интересен для целей этой статьи, мы не будем об этом говорить.
Специальные escape-символы
В char типе также можно хранить специальные escape-символы, то есть последовательности символов, которые вызывают определенное поведение при печати:
- \b эквивалентно backspace, отмене слева (эквивалентно клавише Delete).
- \n эквивалентно переводу строки (эквивалентно клавише Ente).
- \\ равняется только одному \ (только потому, что символ \ используется для escape-символов).
- \t эквивалентно горизонтальной табуляции (эквивалентно клавише TAB).
- \’ эквивалентно одинарной кавычке (одинарная кавычка ограничивает литерал символа).
- \» эквивалентно двойной кавычке (двойная кавычка ограничивает литерал строки).
- \r представляет собой возврат каретки (специальный символ, который перемещает курсор в начало строки).
- \f представляет собой подачу страницы (неиспользуемый специальный символ, представляющий курсор, перемещающийся на следующую страницу документа).
Обратите внимание, что присвоение литерала ‘»‘ символу совершенно законно, поэтому следующий оператор:
System.out.println('"');
что эквивалентно следующему коду:
char doubleQuotes = '"'; System.out.println(doubleQuotes);
правильно и напечатает символ двойной кавычки:
Если бы мы попытались не использовать escape-символ для одиночных кавычек, например, со следующим утверждением:
System.out.println(''');
мы получим следующие ошибки времени компиляции, поскольку компилятор не сможет различить разделители символов:
error: empty character literal System.out.println('''); ^ error: unclosed character literal System.out.println('''); ^ 2 errors
Поскольку разделители строковых литералов представлены в двойных кавычках, ситуация обратная. Фактически, внутри строки можно заключить одинарные кавычки:
System.out.println("'IQ'");
С другой стороны, мы должны использовать \» escape-символ, чтобы использовать двойные кавычки в строке. Итак, следующее утверждение:
System.out.println(""IQ"");
вызовет следующие ошибки компиляции:
error: ')' expected System.out.println(""IQ""); ^ error: ';' expected System.out.println(""IQ""); ^ 2 errors
Вместо этого верна следующая инструкция:
System.out.println("\"IQ\"");
Написание Java кода в формате Unicode
Литеральный формат Unicode также можно использовать для замены любой строки нашего кода. Фактически, компилятор сначала преобразует формат Unicode в символ, а затем оценивает синтаксис. Например, мы могли бы переписать следующий оператор:
int i = 8;
\u0069\u006E\u0074 \u0069 \u003D \u0038\u003B
Фактически, если мы добавим к предыдущей строке следующий оператор:
System.out.println("i bash">i = 8
Несомненно, это бесполезный способ написания нашего кода. Но может быть полезно знать эту функцию, поскольку она позволяет нам понять некоторые ошибки, которые (редко) случаются.
Формат Unicode для escape-символов
Тот факт, что компилятор преобразует шестнадцатеричный формат Unicode перед оценкой кода, имеет некоторые последствия и оправдывает существование escape-символов. Например, давайте рассмотрим символ перевода строки, который можно представить с помощью escape-символа \n . Теоретически перевод строки связан в кодировке Unicode с десятичным числом 10 (что соответствует шестнадцатеричному числу A). Но, если мы попытаемся определить его в формате Unicode:
char lineFeed = '\u000A';
мы получим следующую ошибку времени компиляции:
error: illegal line end in character literal char lineFeed = '\u000A'; ^ 1 error
В реальности, компилятор преобразует предыдущий код в следующий перед его оценкой:
char lineFeed = ' ';
Формат Unicode был преобразован в символ новой строки, и предыдущий синтаксис не является допустимым синтаксисом для компилятора Java.
Аналогично, символ одинарной кавычки ‘ , который соответствует десятичному числу 39 (эквивалентно шестнадцатеричному числу 27) и который мы можем представить с помощью escape-символа \’, не может быть представлен в формате Unicode:
char singleQuote = '\u0027';
Также в этом случае компилятор преобразует предыдущий код следующим образом:
char singleQuote = ''';
что приведет к следующим ошибкам времени компиляции:
error: empty character literal char singleQuote = '\u0027'; ^ error: unclosed character literal char singleQuote = '\u0027'; ^ 2 errors
Первая ошибка связана с тем, что первая пара кавычек не содержит символа, а вторая ошибка указывает на то, что указание третьей одинарной кавычки является незакрытым символьным литералом.
Также есть проблемы с символом возврата каретки, представленным шестнадцатеричным числом D (соответствующим десятичному числу 13) и уже представленным с помощью escape-символа \r . Фактически, если мы напишем:
char carriageReturn = '\u000d';
мы получим следующую ошибку времени компиляции:
error: illegal line end in character literal char carriageReturn = '\u000d'; ^ 1 error
Фактически, компилятор преобразовал число в формате Unicode в возврат каретки, вернув курсор в начало строки, и то, что должно было быть второй одинарной кавычкой, стало первой.
Что касается символа , , представленного десятичным числом 92 (соответствующего шестнадцатеричному числу 5C) и представленного escape-символом \ , если мы напишем:
char backSlash = '\u005C';
мы получим следующую ошибку времени компиляции:
error: unclosed character literal char backSlash = '\u005C'; ^ 1 error
Это потому, что предыдущий код будет преобразован в следующий:
char backSlash = '\';
и поэтому пара символов ‘ рассматривается как escape-символ, соответствующий одинарной кавычке, и поэтому в буквальном закрытии отсутствует другая одинарная кавычка.
С другой стороны, если мы рассмотрим символ » , представленный шестнадцатеричным числом 22 (соответствующий десятичному числу 34) и представленный escape-символом » , если мы напишем:
char quotationMark = '\u0022';
проблем не будет. Но если мы используем этот символ внутри строки:
String quotationMarkString = "\u0022";
мы получим следующую ошибку времени компиляции:
error: unclosed string literal String quotationMarkString = "\u0022"; ^ 1 error
поскольку предыдущий код будет преобразован в следующий:
String quotationMarkString = """;
Тайна ошибки комментария
Еще более странная ситуация возникает при использовании однострочных комментариев для форматов Unicode, таких как возврат каретки или перевод строки. Например, несмотря на то, что оба следующих оператора закомментированы, могут возникнуть ошибки во время компиляции!
// char lineFeed = '\u000A'; // char carriageReturn = '\u000d';
Это связано с тем, что компилятор всегда преобразует шестнадцатеричные форматы с помощью символов перевода строки и возврата каретки, которые несовместимы с однострочными комментариями; они печатают символы вне комментария!
Чтобы разрешить ситуацию, используйте обозначение многострочного комментария, например:
/* char lineFeed = '\u000A'; char carriageReturn = '\u000d'; */
Другая ошибка, из-за которой программист может потерять много времени, — это использование последовательности \u в комментарии. Например, со следующим комментарием мы получим ошибку времени компиляции:
/* * The file will be generated inside the C:\users\claudio folder */
Если компилятор не находит допустимую последовательность из 4 шестнадцатеричных символов после \u , он выведет следующую ошибку:
error: illegal unicode escape * The file will be generated inside the C:\users\claudio folder ^ 1 error
Выводы
В этой статье мы увидели, что использование типа char в Java скрывает некоторые действительно удивительные особые случаи. В частности, мы увидели, что можно писать код Java, используя формат Unicode. Это связано с тем, что компилятор сначала преобразует формат Unicode в символ, а затем оценивает синтаксис. Это означает, что программисты могут находить синтаксические ошибки там, где они никогда не ожидали, особенно в комментариях.
Примечание автора: эта статья представляет собой короткий отрывок из раздела 3.3.5 «Примитивные символьные типы данных» тома 1 моей книги «Java для пришельцев». Для получения дополнительной информации посетите сайт книги (вы можете загрузить раздел 3.3.5 из области «Примеры»).
- unicode character properties
- character