При вычислении выражений важен приоритет операторов. Для операторов сложения, вычитания, умножения и деления он “естественный”: умножение и деление обладают одинаковым наиболее высоким приоритетом, а сложение и вычитание – одинаковым приоритетом, который ниже. Таким образом, например,
a*b/c+d
это то же, что
( (a*b)/c )+d
Круглые скобки позволяют группировать элементы выражений, при этом выражение в скобках вычисляется до того, как участвует в вычислении остальной части выражения. То есть скобки обеспечивают больший приоритет, чем все остальные операторы. Поэтому
(a+b)*c будет вычисляться так: сначала вычислится сумма a+b, после чего полученный результат будет умножен на значение c.
Кроме перечисленных в Java имеется большое количество других правил, определяющих приоритеты различных операторов. Автор считает их изучение не только нецелесообразным, но даже вредным: программу следует писать так, чтобы все последовательности действий были очевидны и не могли вызвать сложностей в понимании текста программы и привести к логической ошибке. Поэтому следует расставлять скобки даже в тех случаях, когда они теоретически не нужны, но делают очевидной последовательность действий. Отметим, такие действия часто помогают заодно решить гораздо более сложные проблемы, связанные с арифметическим переполнением.
Далее в справочных целях приведена таблица приоритета операторов. Ей имеет смысл пользоваться в случае анализа плохо написанных программ, когда из текста программы неясна последовательность операторов.
Приори-тет | Группа операторов | Операторы | ||||
1 высший | Постфиксные | ( ) | [ ] | . | ||
2 | Унарные | ++ операнд операнд ++ | --операнд операнд-- | ~ | ! | + операнд - операнд |
3 | Создания объектов и преобразования типа | new | (тип) операнд | |||
4 | Мультипликатив-ные | * | / | % | ||
5 | Аддитивные | + | - | |||
6 | Сдвиги битов | >> | >>> | << | ||
7 | Отношения | > | >= | < | <= | instanceof |
8 | Эквивалентности | == | != | |||
9 | Побитовое И | & | ||||
10 | Побитовое исключающее ИЛИ | ^ | ||||
11 | Побитовое ИЛИ | | | ||||
12 | Логическое И | && | ||||
13 | Логическое ИЛИ | || | ||||
14 | Условный | ? : | ||||
15 низший | Присваивания | = | Оператор= ( +=, -=, *=, /= и т.п. ) |
3.8.Типы-перечисления (enum)
Иногда требуется использовать элементы, которые не являются ни числами, ни строками, но ведут себя как имена элементов и одновременно обладают порядковыми номерами. Например, названия месяцев или дней недели. В этих случаях используют перечисления. Для задания типа какого-либо перечисления следует написать зарезервированное слово enum (сокращение от enumeration – “перечисление”), после которого имя задаваемого типа, а затем в фигурных скобках через запятую элементы перечисления. В качестве элементов можно использовать любые простые идентификаторы (не содержащие квалификаторов вида имя1.имя2).
Тип-перечисление обязан быть глобальным – он может задаваться либо на уровне пакета, либо в каком-либо классе. Но его нельзя задавать внутри какого-либо метода. Элементы перечисления могут иметь любые имена, в том числе совпадающие в разных перечислениях или совпадающие с именами классов или их членов – каждое перечисление имеет своё собственное пространство имён. Доступ к элементу перечисления осуществляется с квалификацией именем типа-перечисления:
ИмяТипа.имяЭлемента
У каждого элемента перечисления имеется порядковый номер, соответствующий его положению в наборе - нумерация начинается с нуля. Поэтому первый элемент имеет номер 0, второй элемент – номер 1, и так далее. Имеется функция ordinal(), возвращающая порядковый номер элемета в перечислении. Также имеется функция compareTo, позволяющая сравнивать два элемента перечисления - она возвращает разницу в их порядковых номерах.
Строковое представление значения можно получить с помощью функции name(). Преобразование из строки в значение типа “перечисление” осуществляется с помощью функции класса valueOf, в которую передаётся строковое представление значения.
Если требуется рассматривать элементы перечисления как массив, можно воспользоваться функцией values() – она возвращает массив элементов, к которым можно обращаться по индексу. Формат вызова функции такой: ИмяТипа.values()
Для примера зададим типы-перечисления Monthes (“месяцы”) и Spring (“весна”), соответствующие различным наборам месяцев:
enum Monthes {jan,feb,mar,apr,may,jun,jul,aug,sept,oct,nov,dec};
enum Spring { march, apr, may };
Названия месяцев мы намеренно пишем со строчной буквы для того, чтобы было понятно, что это идентификаторы переменных, а не типы. А имя марта написано по-разному в типах Monthes и Spring для того, чтобы показать независимость их пространств имён.
Объявление переменных типа “перечисление” делается так же, как для всех остальных типов, при этом переменные могут быть как неинициализированы, так и инициализированы при задании:
public Monthes m1 ,m2=Monthes.mar, m3;
- при задании в классе общедоступных полей m1, m2 и m3,
Spring spr1=Spring.apr, spr2;
- при задании в методе локальной переменной или задании в классе поля spr1 с пакетным уровнем доступа.
После чего возможны следующие операторы:
spr2=spr1;
spr1=Spring.may;
System.out.println("Результат сравнения="+spr2.compareTo(Spring.march));
После выполнения этих операторов в консольное окно будет выведен текст
Результат сравнения=1 ,
поскольку в переменной spr2 окажется значение Spring.apr , порядковый номер которого на 1 больше, чем у значения Spring.march , с которым идёт сравнение.
Пусть в переменной spr2 хранится значение Spring.may. Порядковый номер значения, хранящегося в переменной, можно получить с помощью вызова spr2.ordinal() . Он возвратит число 2, так как may – третий элемент перечисления (сдвиг на 1 получается из-за того, что нумерация начинается с нуля).
Строковое представление значения, хранящегося в переменной spr2, можно получить с помощью вызова spr2.name() . Он возвратит строку “may” - имя типа в возвращаемое значение не входит.
Если переменная типа “перечисление” не инициализирована, в ней хранится значение null. Поэтому вызов
System.out.println("spr2="+spr2);
осуществлённый до присваивания переменной spr2 значения возвратит строку
spr2=null
А вот попытки вызовов spr2.ordinal() или spr2.name() приведут к возникновению ошибки (исключительной ситуации) с диагностикой
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
Получение значения типа Spring по номеру, хранящемуся в переменной i, осуществляется так:
spr1=Spring.values()[i];
Преобразование из строки в значение типа Spring будет выглядеть так:
spr1=Spring.valueOf("march");
- Величины типа boolean принимают значения true или false.
- Логические операторы && -“И”, || - “ИЛИ”, ^ - “Исключающее ИЛИ”, ! – “НЕ” применимы к величинам булевского типа. Логические выражения в Java вычисляются в соответствии с укороченным оцениванием.
- Операторы сравнения применимы к любым величинам a и b одного типа, а также к произвольным числовым величинам a и b, не обязательно имеющим один тип. В качестве оператора сравнения на равенство используется составной символ, состоящий из двух подряд идущих символа равенства “==”.
- В Java имеются встроенные примитивные целые типы byte, short, int, long и символьный тип char, в некотором смысле также являющийся целочисленным. При этом только тип char беззнаковый, все остальные – знаковые.
- Для задания в тексте программы численных литерных констант типа long, выходящих за пределы диапазона чисел типа int, после написания числа следует ставить постфикс – букву L.
- Константами называются именованные ячейки памяти с неизменяемым содержимым. Объявление констант осуществляется в классе, при этом перед именем типа константы ставится комбинация зарезервированных слов public и final.
- В Java имеется два встроенных примитивных вещественных типа float и double (точнее, типы чисел в формате с плавающей точкой).
- Математические функции, а также константы “пи” (Math.PI) и “е” (Math.E ) заданы в классе Math, находящемся в пакете java.lang .
- Целочисленные математические вычисления проводятся на аппаратном уровне только с величинами типа int или long. Для величин типа byte, short или char сначала происходит преобразование в тип int, после чего производится их подстановка в качестве операндов. Если же один из операндов имеет тип long, действия производятся с числами типа long, поскольку второй операнд автоматически преобразуется к этому типу.
- При работе с вещественными величинами в Java возможна работа на аппаратном уровне только с операндами типов float и double. Если один из операндов имеет тип double, а другой float, действия производятся с числами типа double, поскольку операнд типа float автоматически преобразуется к типу double.