sonyps4.ru

Основные операторы Java.

Java предоставляет богатый набор операторов для управления переменными. Все операторы Java можно разделить на следующие группы:

  • арифметические операторы;
  • операторы сравнения;
  • побитовые операторы;
  • логические операторы;
  • операторы присваивания;
  • прочие операторы.

Арифметические операторы

Арифметические операторы - используются в математических выражениях таким же образом, как они используются в алгебре. Предположим, целая переменная A равна 10, а переменная B равна 20. В следующей таблице перечислены арифметические операторы в Java:

Пример

Следующий простой пример показывает программно арифметические операторы. Скопируйте и вставьте следующий java-код в файл test.java, скомпилируйте и запустить эту программу:

Public class Test { public static void main(String args) { int a = 10; int b = 20; int c = 25; int d = 25; System.out.println("a + b = " + (a + b)); System.out.println("a - b = " + (a - b)); System.out.println("a * b = " + (a * b)); System.out.println("b / a = " + (b / a)); System.out.println("b % a = " + (b % a)); System.out.println("c % a = " + (c % a)); System.out.println("a++ = " + (a++)); System.out.println("b-- = " + (a--)); // Проверьте разницу в d++ и ++d System.out.println("d++ = " + (d++)); System.out.println("++d = " + (++d)); } }

A + b = 30 a - b = -10 a * b = 200 b / a = 2 b % a = 0 c % a = 5 a++ = 10 b-- = 11 d++ = 25 ++d = 27

Операторы сравнения

Есть следующие операторы сравнения, поддерживаемые на языке Java. Предположим, переменная A равна 10, а переменная B равна 20. В следующей таблице перечислены реляционные операторы или операторы сравнения в Java:

Оператор Описание Пример
== Проверяет, равны или нет значения двух операндов, если да, то условие становится истинным (A == B) - не верны
!= Проверяет, равны или нет значения двух операндов, если значения не равны, то условие становится истинным (A != B) - значение истинна
> Проверяет, является ли значение левого операнда больше, чем значение правого операнда, если да, то условие становится истинным (A > B) - не верны
Проверяет, является ли значение левого операнда меньше, чем значение правого операнда, если да, то условие становится истинным (A
>= Проверяет, является ли значение левого операнда больше или равно значению правого операнда, если да, то условие становится истинным (A >= B) - значение не верны
Проверяет, если значение левого операнда меньше или равно значению правого операнда, если да, то условие становится истинным (A

Пример

Следующий простой пример показывает, программно операторы сравнения в Java. Скопируйте и вставьте следующий java-код в файл test.java, скомпилируйте и запустить эту программу:

Public class Test { public static void main(String args) { int a = 10; int b = 20; System.out.println("a == b = " + (a == b)); System.out.println("a != b = " + (a != b)); System.out.println("a > b = " + (a > b)); System.out.println("a = a = " + (b >= a)); System.out.println("b

A == b = false a != b = true a > b = false a = a = true b

Побитовые операторы

Java определяет несколько побитовых операторов, которые могут быть применены для целочисленных типов: int, long, short, char и byte. В Java побитовый оператор работает над битами и выполняет операцию бит за битом. Предположим, если a = 60; и b = 13; то в двоичном формате они будут следующие:

a = 0011 1100
b = 0000 1101
-----------------
a&b = 0000 1100
a|b = 0011 1101
a^b = 0011 0001
~a = 1100 0011

Предположим целочисленные переменная A равна 60, а переменная B равна 13. В следующей таблице перечислены побитовые операторы в Java:

Оператор Описание Пример
& (побитовое и) Бинарный оператор AND копирует бит в результат, если он существует в обоих операндах. (A & B) даст 12, который является 0000 1100
| (побитовое или) Бинарный оператор OR копирует бит, если он существует в любом из операндов. (A | B) даст 61 который равен 0011 1101
^ (побитовое логическое или) Бинарный оператор XOR копирует бит, если он установлен в одном операнде, но не в обоих. (A ^ B) даст 49, которая является 0011 0001
~ (побитовое дополнение) Бинарный оператор дополнения и имеет эффект «отражения» бит. (~ A) даст -61, которая является формой дополнением 1100 0011 в двоичной записи
Бинарный оператор сдвига влево. Значение левых операндов перемещается влево на количество бит, заданных правым операндом. A
>> (сдвиг вправо) Бинарный оператор сдвига вправо. Значение правых операндов перемещается вправо на количество бит, заданных левых операндом. A >> 2 даст 15, который является 1111
>>> (нулевой сдвиг вправо) Нулевой оператор сдвига вправо. Значение левых операндов перемещается вправо на количество бит, заданных правым операндом, а сдвинутые значения заполняются нулями. A >>> 2 даст 15, который является 0000 1111

Пример

Следующий простой пример показывает, программно побитовые операторы в Java. Скопируйте и вставьте следующий java-код в файл test.java, скомпилируйте и запустить эту программу:

Public class Test { public static void main(String args) { int a = 60; /* 60 = 0011 1100 */ int b = 13; /* 13 = 0000 1101 */ int c = 0; c = a & b; /* 12 = 0000 1100 */ System.out.println("a & b = " + c); c = a | b; /* 61 = 0011 1101 */ System.out.println("a | b = " + c); c = a ^ b; /* 49 = 0011 0001 */ System.out.println("a ^ b = " + c); c = ~a; /*-61 = 1100 0011 */ System.out.println("~a = " + c); c = a > 2; /* 215 = 1111 */ System.out.println("a >> 2 = " + c); c = a >>> 2; /* 215 = 0000 1111 */ System.out.println("a >>> 2 = " + c); } }

Будет получен следующий результат:

A & b = 12 a | b = 61 a ^ b = 49 ~a = -61 a > 15 a >>> 15

Логические операторы

Предположим, логическая переменная A имеет значение true, а переменная B хранит false. В следующей таблице перечислены логические операторы в Java:

Пример

Public class Test { public static void main(String args) { boolean a = true; boolean b = false; System.out.println("a && b = " + (a&&b)); System.out.println("a || b = " + (a||b)); System.out.println("!(a && b) = " + !(a && b)); } }

Это произведет следующий результат:

A && b = false a || b = true !(a && b) = true

Операторы присваивания

Существуют следующие операторы присваивания, поддерживаемые языком Java:

Оператор Описание Пример
= Простой оператор присваивания, присваивает значения из правой стороны операндов к левому операнду C = A + B, присвоит значение A + B в C
+= Оператор присваивания «Добавления», он присваивает левому операнду значения правого C += A, эквивалентно C = C + A
-= Оператор присваивания «Вычитания», он вычитает из правого операнда левый операнд C -= A, эквивалентно C = C - A
*= Оператор присваивания «Умножение», он умножает правый операнд на левый операнд C * = A эквивалентно C = C * A
/= Оператор присваивания «Деление», он делит левый операнд на правый операнд C /= A эквивалентно C = C / A
%= Оператор присваивания «Модуль», он принимает модуль, с помощью двух операндов и присваивает его результат левому операнду C %= A, эквивалентно C = C % A
Оператор присваивания «Сдвиг влево» C
>>= Оператор присваивания «Сдвиг вправо» C >>= 2, это как C = C >> 2
&= Оператор присваивания побитового «И» («AND») C &= 2, это как C = C & 2
^= Оператор присваивания побитового исключающего «ИЛИ» («XOR») C ^= 2, это как C = C ^ 2
|= Оператор присваивания побитового «ИЛИ» («OR») C |= 2, это как C = C | 2

Пример

Следующий простой пример показывает, программно логические операторы в Java. Скопируйте и вставьте следующий java-код в файл test.java, скомпилируйте и запустить эту программу:

Public class Test { public static void main(String args) { int a = 10; int b = 20; int c = 0; c = a + b; System.out.println("c = a + b = " + c); c += a ; System.out.println("c += a = " + c); c -= a ; System.out.println("c -= a = " + c); c *= a ; System.out.println("c *= a = " + c); a = 10; c = 15; c /= a ; System.out.println("c /= a = " + c); a = 10; c = 15; c %= a ; System.out.println("c %= a = " + c); c >= 2 ; System.out.println("c >>= 2 = " + c); c >>= 2 ; System.out.println("c >>= a = " + c); c &= a ; System.out.println("c &= 2 = " + c); c ^= a ; System.out.println("c ^= a = " + c); c |= a ; System.out.println("c |= a = " + c); } }

Будет получен следующий результат:

C = a + b = 30 c += a = 40 c -= a = 30 c *= a = 300 c /= a = 1 c %= a = 5 c >= 2 = 5 c >>= 2 = 1 c &= a = 0 c ^= a = 10 c |= a = 10

Прочие операторы

Есть несколько других операторов, поддерживаемых языком Java.

Тернарный оператор или условный оператор (?:)

Тернарный оператор - оператор, который состоит из трех операндов и используется для оценки выражений типа boolean. Тернарный оператор в Java также известен как условный оператор. Этот. Цель тернарного оператора или условного оператора заключается в том, чтобы решить, какое значение должно быть присвоено переменной. Оператор записывается в виде:

Переменная x = (выражение) ? значение if true: значение if false

Пример

Ниже приведен пример:

Public class Test { public static void main(String args){ int a , b; a = 10; b = (a == 1) ? 20: 30; System.out.println("Значение b: " + b); b = (a == 10) ? 20: 30; System.out.println("Значение b: " + b); } }

Будет получен следующий результат:

Значение b: 30 Значение b: 20

Оператор instanceof

Оператор instanceof - проверяет, является ли объект определенного типа (типа класса или типа интерфейса) и используется только для переменных ссылочного объекта. Оператор instanceof записывается в виде:

(Переменная ссылочного объекта) instanceof (класс/тип интерфейса)

Примеры

Если переменная ссылочного объекта в левой части оператора проходит проверку для класса/типа интерфейса на правой стороне, результатом будет значение true. Ниже приведен пример и описание оператора instanceof:

Public class Test { public static void main(String args){ String name = "Олег"; // Следующее вернётся верно, поскольку тип String boolean result = name instanceof String; System.out.println(result); } }

Будет получен следующий результат:

Этот оператор по-прежнему будет возвращать значение true, если сравниваемый объект является совместимым с типом на право назначения. Ниже приводится еще один пример:

Class Vehicle {} public class Car extends Vehicle { public static void main(String args){ Vehicle a = new Car(); boolean result = a instanceof Car; System.out.println(result); } }

Будет получен следующий результат:

Приоритет операторов в Java

Приоритет операторов определяет группирование терминов в выражении. Это влияет как вычисляется выражение. Некоторые операторы имеют более высокий приоритет, чем другие; например оператор умножения имеет более высокий приоритет, чем оператор сложения:

Например, x = 7 + 3 * 2. Здесь x присваивается значение 13, не 20, потому что оператор «*» имеет более высокий приоритет, чем «+», так что сначала перемножается «3 * 2», а затем добавляется «7».

В таблице операторы с наивысшим приоритетом размещаются в верхней части, и уровень приоритета снижается к нижней части таблицы. В выражении высокий приоритет операторов в Java будет оцениваться слева направо.

Категория Оператор Ассоциативность
Постфикс () . (точка) Слева направо
Унарный ++ - - ! ~ Справа налево
Мультипликативный * / % Слева направо
Аддитивный + - Слева направо
Сдвиг >> >>> Слева направо
Реляционный > >= Слева направо
Равенство == != Слева направо
Побитовое «И» («AND») & Слева направо
Побитовое исключающее «ИЛИ» («XOR») ^ Слева направо
Побитовое «ИЛИ» («OR») | Слева направо
Логическое «И» («AND») && Слева направо
Логическое «ИЛИ» («OR») || Слева направо
Условный ?: Справа налево
Присваивание = += -= *= /= %= >>= Справа налево
Запятая , Слева направо

В следующем уроке поговорим об управлении циклом в программировании на Java. В этом уроке будут описаны различные типы циклов, как циклы могут быть использованы в разработке программ, и для каких целей они используются.

Для целых числовых типов данных - long, int, short, char и byte - определен дополнительный набор операторов, с помощью которых можно проверять и модифицировать состояние отдельных битов соответствующих значений. В таблице 4.2 приведена сводка таких операторов. Операторы битовой арифметики работают с каждым битом как с самостоятельной величиной.

Таблица 4.2. Операторы битовой арифметики

Оператор

Результат

Оператор

Результат

побитовое И (AND)

Побитовое И (AND) с присваиванием

побитовое ИЛИ (OR)

побитовое ИЛИ (OR) с присваиванием

побитовое исключающее ИЛИ (XOR)

побитовое исключающее ИЛИ (XOR) с присваиванием

сдвиг вправо

сдвиг вправо с присваиванием

сдвиг вправо с заполнением нулями

сдвиг вправо с заполнением нулями с присваиванием

сдвиг влево

сдвиг влево с присваиванием

побитовое унарное отрицание (NOT)

В таблице 4.3 показано, как каждый из операторов битовой арифметики воздействует на возможные комбинации битов своих операндов.

Таблица 4.3

Сдвиг влево

Оператор << выполняет сдвиг влево всех битов своего левого операнда на число позиций, заданное правым операндом. При этом часть битов в левых разрядах выходит за границы и теряется, а соответствующие правые позиции заполняются нулями.

Сдвиг вправо

Оператор >> означает в языке Java сдвиг вправо. Он перемещает все биты своего левого операнда вправо на число позиций, заданное правым операндом. Когда биты левого операнда выдвигаются за самую правую позицию слова, они теряются. При сдвиге вправо освобождающиеся старшие (левые) разряды сдвигаемого числа заполняются предыдущим содержимым знакового разряда. Сделано это для того, чтобы при сдвиге вправо числа сохраняли свой знак.

Беззнаковый сдвиг вправо

Часто требуется, чтобы при сдвиге вправо расширение знакового разряда не происходило, а освобождающиеся левые разряды заполнялись бы нулями. С этой целью используется оператор беззнакового сдвига вправо >>>.

4.3. Операторы отношений

Для того чтобы можно было сравнивать два значения, в Java имеется набор операторов, описывающих отношение и равенство. Список таких операторов приведен в таблице 4.4.

Таблица 4.4

Оператор

Результат

равно

не равно

больше

меньше

больше или равно

меньше или равно

Значения любых типов, включая целые и вещественные числа, символы, логические значения и ссылки, можно сравнивать, используя оператор проверки на равенство == и неравенство!=. Обратите внимание - в языке Java проверка на равенство обозначается последовательностью (==). Один знак (=) - это оператор присваивания.

Операторы отношения могут применяться только к операндам числовых типов. С их помощью можно работать с целыми, вещественными и символьными типами. Каждый из операторов отношения возвращает результат типа boolean, т.е. либоtrue , либоfalse .

В Java есть операторы сдвига. Операторы << и >> позаимствованы из С/C++. Кроме того, Java обладает своим новым оператором сдвига >>>.

Операторы сдвига присущи системам, которые могут выравнивать биты, прочтённые из IO портов или зартсываемые в IO порты. Это также быстрое умножение или деление на степень двойки. Преимущество операторов сдвига в Java - это независимость от платформы. Поэтому вы можете использовать их не беспокоясь ни о чём.

Основы сдвига

Сдвиг - это, по сути, простейшая операция: мы берём последовательность битов и двигаем её влево или вправо. Больше всего конфуза вызывает оператор >>>. Но о нём мы поговорим чуть позже.

Операторы сдвига могут применяться лишь к целым числам, то есть к типам int или long . Следующая таблица иллюстрирует базовый механизм сдвига.

Таблица 1: Идея сдвига

Исходные данные
Бинарное представление 00000000 00000000 00000000 11000000
Сдвиг влево на 1 бит 00000000 00000000 00000001 1000000?
Сдвиг вправо на бит ?0000000 00000000 00000000 01100000 0
Сдвиг влево на 4 бита 0000 00000000 00000000 00001100 0000????
Исходные данные
Бинарное представление 11111111 11111111 11111111 01000000
Сдвиг влево на 1 бит 11111111 11111111 11111110 1000000?
Сдвиг вправо на бит ?1111111 11111111 11111111 10100000 0

Таблица показывает фундаментальную идею сдвига: перемещение битов относительно их позиций. Это как очередь в магазине: как только один человек совершил покупку и отшёл, вся очередь сдвинулась и позиции всех участников очереди изменились.

Однако, глядя на таблицу, возникают три вопроса вопроса:

  1. Что происходит, если мы сдвигаем влево и при этом часть бинарной записи выходит за границу слева, а часть - остаётся пустой справа?
  2. Что происходит, когда справа - выход за границы, а слева - пустое место?
  3. Какое истинное значение принимает знак "?"?.

Ответим на часть этих вопросов. Биты, вышедшие за границы, просто теряются. Мы о них забываем.

В некоторых языках, типа ассемблер, есть операция ротации , когда при сдвиге вышедшие за границы биты не теряются, но ставятся на освободившееся место (вместо вопросиков). Однако языки высокого уровня, типа Java, не имеют в своём арсенале такой операции.

Сдвиг отрицательных чисел

Ответ на вопрос о значении символов "?" в приведенной выше таблице требует отдельного рассмотрения.

В случае сдвига влево << и беззнакового сдвига вправо >>> новые биты просто устанавливаются в ноль. В случае сдвига вправо со знаком >> новые биты принимают значение старшего (самого левого) бита перед сдвигом. Следующая таблица демонстрирует это:

Таблица 2: Сдвиг положительных и отрицательных чисел

Исходные данные
Бинарное представление 00000000 00000000 00000000 11000000
Сдвиг вправо на 1 бит 00000000 00000000 00000000 01100000
Сдвиг вправо на 7 бит 00000000 00000000 00000000 00000001
Исходные данные
Бинарное представление 11111111 11111111 11111111 01000000
Сдвиг вправо на 1 бит 11111111 11111111 11111111 10100000
Сдвиг вправо на 7 бит 11111111 11111111 11111111 11111110

Заметьте: в том, случае, где старший бит был 0 перед сдвигом, новые биты стали тоже 0. Там где старший бит перед сдвигом был 1, новые биты тоже заполнились 1.

Это правило может показаться странным на первый взгляд. Но оно имеет под собой очень серьёзное обоснование. Если мы сдвигаем бинарное число влево на одну позицию, то в десятичной записи мы умножаем его на два. Если мы сдвигаем влево на n позиций, то умножение происходит на 2 n , то есть на 2, 4, 8, 16 и т.д.

Сдвиг вправо даёт деление на степени двойки. При этом, добавление слева нулей на появившиеся биты на самом деле даёт деление на степени двойки лишь в случае положительных чисел. Но для отрицательных чисел всё совсем по другому!

Как известно, старший бит отрицательных чисел равен единице, 1. Для того, чтобы сохранить старшинство единицы при сдвиге, то есть сохранить отрицательный знак результата деления отрицательного числа на положительное (степень двойки), нам нужно подставлять единицы на освободившиеся места.

Если мы посмотрим на Таблицу 2, то заметим, что 192, сдвинутое на 1 бит вправо - это 192/2=96, а сдвинутое на 7 битов вправо - это 192/2 7 =192/128=1 по законам целочисленной арифметики. С другой стороны, -192 сдвинутое на 1 бит вправо - это 192/2=-96 и т.д.

Есть, однако пример, когда реультат сдвига вправо отличается от результата целочисленного деления на 2. Это случай, когда аргумент = -1. При целочисленном делении мы имеем: -1/2=0. Но результат сдвига вправо нам даёт -1. Это можно трактовать так: целочисленное деление округляет к нулю, а сдвиг округляет к -1.

Таким образом, сдвиг вправо имеет две ипостаси: одна (>>>) просто сдвигает битовый паттерн "в лоб", а другая (>>) сохраняет эквивалентность с операцией деления на 2.

Зачем же Java потребовался беззнаковый сдвиг вправо (сдвиг "в лоб"), когда ни в С, ни в С++ его не существует? Ответ прост, потому что в С и С++ сдвиг всегда беззнаковый . То есть >>>> в Java - это и есть сдвиг вправо в C и C++. Но, поскольку в Java все численные типы со знаком (за исключением char ), то и результаты сдвигов должны иметь знаки.

Сокращение (reduction) правого операнда

На самом деле у операторов сдвига есть правый операнд - число позиций, на которое нужно произвести сдвиг. Для корректного сдвига это число должно быть меньше, чем количество битов в результате сдвига. Если число типа int (long) , то сдвиг не может быть сделан более, чем на 32 (64) бита.

Оператор же сдвига не делает никаких проверок данного условия и допускает операнды, его нарушающие. При этом правый операнд сокращается по модулю от нужного количества битов. Например, если вы захотите сдвинуть целое число на 33 бита, то сдвиг произойдёт на 33%32=1 бит. В результатае такого сдвига мы легко можем получить аномальные результаты, то есть результаты, которых мы не ожидали. Например, при сдвиге на 33 бита мы ожидаем получить 0 или -1 (в знаковой арифметике). Но это не так.

Почему Java сокращает правый операнд оператора сдвига или грустная история о заснувшем процессоре

Одной из главной причин введения сокращения было то, что процессоры сами сокращают подобным образом правый операнд оператора сдвига. Почему?

Несколько лет назад был создан мощнейший процессор с длинными регистрами и операциями ротации и сдвигам на любое количество битов. Именно потому, что регистры были длинными, корректное выполнение этих операций требовало несколько минут.

Основным применением данных процессоров был контроль систем реального времени. В данных системах самый быстрый ответ на внешнее событие должно занимать не более задержки на прерывание (interrupt latency ). Отдельные инскрукции таких процессоров были неделимы. Поэтому выполнение длинных операций (сдвига на несколько бит и ротации) нарушало эффективную работу процессора.

Следующая версия процессора имплементировала эти операции уже по-другому: размер правого операнда сократился. Задержка на прерывание восстанавилась. И многие процессоры переняли данную практику.

Арифметическое распространение (promotion ) операндов

Апифметическое распространение операндов происходит перед применением оперции сдвига и гарантирует, что операнды по крайней мере типа int . Это явление имеет особый эффект на беззнаковый сдвиг вправо, когда сдвигаемое число меньше, чем int : мы получаем не тот результат, который ожидали.

Следующая таблица показывает пример аномалии:

Таблица 3: Арифметическое распространение для беззнакового сдвига вправо, когда операнд меньше, чем int

Исходные данные (-64 в десятичной записи)
Распространение до int 11111111 11111111 11111111 11000000
Сдвиг вправо на 4 битa 00001111 11111111 11111111 11111100
Сокращение до байта 11111100
Ожидаемый результат был 00001100

Мне кажется, давно уже пора приступить к разработке документа, в котором будет четко оговорено, что граждане могут делать в свое свободное время, а чего они делать не должны.

Из к/ф «Забытая мелодия для флейты»

Все операторы Java можно разделить на четыре группы: арифметические, логиче- ские, побитовые и сравнения. Рассмотрим последовательно каждую группу опе- раторов. Начнем с арифметических. Эти операторы перечислены в табл. 1.2.


Таблица 1.2. Арифметические операторы Java

Оператор Название Пояснение
+ Сложение Бинарный оператор. Результатом команды a+b являет- ся сумма значений переменных a и b
- Вычитание Бинарный оператор. Результатом команды a-b являет- ся разность значений переменных a и b
* Умножение Бинарный оператор. Результатом команды a*b являет- ся произведение значений переменных a и b
/ Деление Бинарный оператор. Результатом команды a/b являет- ся частное от деления значений переменных a и b. Для целочисленных операндов по умолчанию выполняется деление нацело
% Остаток Бинарный оператор. Результатом команды a%b яв- ляется остаток от целочисленного деления значений переменных a и b
+= Сложение (упро- щенная форма с присваиванием) Упрощенная форма оператора сложения с присваива- нием. Команда a+=b является эквивалентом команды a=a+b
-= Вычитание (упро- щенная форма с присваиванием) Упрощенная форма оператора вычитания с присваива- нием. Команда a-=b является эквивалентом команды a=a-b
*= Умножение (упро- щенная форма с присваиванием) Упрощенная форма оператора умножения с присваи- ванием. Команда a*=b является эквивалентом команды a=a*b
/= Деление (упро- щенная форма с присваиванием) Упрощенная форма оператора деления с присваива- нием. Команда a/=b является эквивалентом команды a=a/b
%= Остаток (упро- щенная форма) Упрощенная форма оператора вычисления остатка с присваиванием. Команда a%=b является эквивален- том команды a=a%b
++ Инкремент Унарный оператор. Команда a++ (или ++a) является эквивалентом команды a=a+1
-- Декремент Унарный оператор. Команда a-- (или --a) является эквивалентом команды a=a-1

Эти операторы имеют некоторые особенности. В первую очередь обращаем вни- мание на оператор деления /. Если операндами являются целые числа, в ка- честве значения возвращается результат целочисленного деления. Рассмотрим последовательность команд:

int a=5,b=2; double x=a/b;

В данном примере переменная x получает значение 2.0, а не 2.5, как можно было бы ожидать. Дело в том, что сначала вычисляется выражение a/b. Поскольку


операнды целочисленные, выполняется целочисленное деление. И только по- сле этого полученное значение преобразуется к формату double и присваивается переменной x.

Для того чтобы при целочисленных операндах выполнялось обычное деление, перед выражением с оператором деления указывается в круглых скобках иден- тификатор типа double (или float). Например, так:

double x=(double)a/b;

Теперь значение переменной x равно 2.5.

В Java, как и в С++, есть группа упрощенных арифметических операторов с присваиванием. Если op - один из операторов сложения, умножения, деления и вычисления остатка, то упрощенная форма этого оператора с присваиванием имеет вид op=. Это тоже бинарный оператор, как и оператор op, а команда вида x op=y является эквивалентом команды x=x op y.

Еще два исключительно полезных унарных оператора - операторы инкремента (++) и декремента (--). Действие оператора декремента сводится к увеличению на единицу значения операнда, а оператор декремента на единицу уменьшает операнд. Другими словами, команда x++ эквивалентна команде x=x+1, а команда x-- эквивалентна команде x=x-1. У операторов инкремента и декремента есть не только представленная здесь постфиксная форма (оператор следует после опе- ранда: x++ или x--), но и префиксная (оператор располагается перед операндом:

X или --x). С точки зрения действия на операнд нет разницы в том, префикс- ная или постфиксная формы оператора использованы. Однако если выражение с оператором инкремента или декремента является частью более сложного вы- ражения, различие в префиксной и постфиксной формах операторов инкремента и декремента существует. Если использована префиксная форма оператора, сна- чала изменяется значение операнда, а уже после этого вычисляется выражение. Если использована постфиксная форма оператора, сначала вычисляется выраже- ние, а затем изменяется значение операнда. Рассмотрим небольшой пример:

В этом случае после выполнения команд переменная n будет иметь значение 11, а переменная m - значение 10. На момент выполнения команды m=n++ значение переменной n равно 10. Поскольку в команде m=n++ использована постфиксная форма оператора инкремента, то сначала выполняется присваивание значения переменной m, а после этого значение переменной n увеличивается на единицу.

Иной результат выполнения следующих команд:


Обе переменные (n и m) в этом случае имеют значение 11. Поскольку в команде m=++n использована префиксная форма инкремента, сначала на единицу увели- чивается значение переменной n, а после этого значение переменной n присваи- вается переменной m.

Следующую группу образуют логические операторы. Операндами логических операторов являются переменные и литералы типа boolean. Логические опера- торы Java перечислены в табл. 1.3.

Таблица 1.3. Логические операторы Java

Оператор Название Пояснение
& Логическое И Бинарный оператор. Результатом операции A&B явля- ется true, если значения обоих операндов равны true. В противном случае возвращается значение false
&& Сокращенное логическое И Бинарный оператор. Особенность оператора, по срав- нению с оператором &, состоит в том, что если значе- ние первого операнда равно false, то значение второго операнда не проверяется
| Логическое ИЛИ Бинарный оператор. Результатом операции A|B являет- ся true, если значение хотя бы одного операнда равно true. В противном случае возвращается значение false
|| Сокращенное логическое ИЛИ Бинарный оператор. Особенность оператора, по срав- нению с оператором |, состоит в том, что если значе- ние первого операнда равно true, то значение второго операнда не проверяется
^ Исключающее ИЛИ Бинарный оператор. Результатом операции A^B являет- ся true, если значение одного и только одного опе- ранда равно true. В противном случае возвращается значение false
! Логическое отрицание Унарный оператор. Результатом команды!A является true, если значение операнда A равно false. Если зна- чение операнда A равно true, результатом команды!A является значение false

Логические операторы обычно используются в качестве условий в условных операторах и операторах цикла.

В табл. 1.4 перечислены операторы сравнения, используемые в Java.

Таблица 1.4. Операторы сравнения Java


Оператор Название Пояснение
< Меньше Результатом операции A
<= Меньше или равно Результатом операции A<=B является значения true, если значение операнда A не больше значения операн- да B. В противном случае значением является false
> Больше Результатом операции A>B является значения true, если значение операнда A больше значения операнда B. В противном случае значением является false
>= Больше или равно Результатом операции A>=B является значения true, если значение операнда A не меньше значения опе- ранда B. В противном случае значением является false
!= Не равно Результатом операции A!=B является значения true, если операнды A и B имеют разные значения. В про- тивном случае значением является false

Операторы сравнения обычно используются совместно с логическими операто- рами.

Для понимания принципов работы поразрядных операторов необходимо иметь хотя бы элементарные познания о двоичном представлении чисел. Напомним читателю некоторые основные моменты.

‰ В двоичном представлении позиционная запись числа содержит нули и еди- ницы.

‰ Старший бит (самый первый слева) определяет знак числа. Для положитель- ных чисел старший бит равен нулю, для отрицательных - единице.

‰ Перевод из двоичной системы счисления положительного числа с позицион-


ной записью


bnbn -1...b 2b 1b 0


(bi могут принимать значения 0 или 1, старший


бит для положительных чисел bn = 0) в десятичную выполняется так:



n -1 n





+ ... + bn -12



‰ Для перевода отрицательного двоичного числа в десятичное представление производится побитовое инвертирование кода (об операции побитового ин- вертирования - см. далее), полученное двоичное число переводится в деся- тичную систему, к нему прибавляется единица (и добавляется знак минус).

‰ Для перевода отрицательного числа из десятичной в двоичную систему от модуля числа отнимают единицу, результат переводят в бинарный код и затем этот код инвертируют.

‰ Умножение числа на два эквивалентно сдвигу влево на один бит позиционной записи числа (с заполнением первого бита нулем).

Побитовые операторы Java описаны в табл. 1.5.


Таблица 1.5. Побитовые операторы Java

Оператор Название Пояснение
& Побитовое И Бинарный оператор. Логическая операция И приме- няется к каждой паре битов операндов. Результатом является 1, если каждый из двух сравниваемых битов равен 1. В противном случае результат равен 0
| Побитовое ИЛИ Бинарный оператор. Логическая операция ИЛИ при- меняется к каждой паре битов операндов. Результатом является 1, если хотя бы один из двух сравниваемых битов равен 1. В противном случае результат равен 0
^ Побитовое ИСКЛЮЧА- ЮЩЕЕ ИЛИ Бинарный оператор. Логическая операция ИСКЛЮЧАЮЩЕЕ ИЛИ применяется к каждой паре битов операндов. Результатом является 1, если один и только один из двух сравниваемых битов равен 1. В противном случае результат равен 0
~ Побитовое отрицание Унарный оператор. Выполняется инверсия двоичного кода: 0 меняется на 1, а 1 меняется на 0
>> Сдвиг вправо Бинарный оператор. Результатом является число, получаемое сдвигом вправо в позиционном пред- ставлении первого операнда (слева от оператора) на количество битов, определяемых вторым операндом (справа от оператора). Исходное значение перво- го операнда при этом не меняется. Младшие биты теряются, а старшие заполняются дублированием знакового бита
<< Сдвиг влево Бинарный оператор. Результатом является число, получаемое сдвигом влево в позиционном представле- нии первого операнда (слева от оператора) на количе- ство битов, определяемых вторым операндом (справа от оператора). Исходное значение первого операнда при этом не меняется. Младшие биты заполняются нулями, а старшие теряются
>>> Беззнаковый сдвиг вправо Бинарный оператор. Результатом является число, по- лучаемое сдвигом вправо в позиционном представле- нии первого операнда (слева от оператора) на количе- ство битов, определяемых вторым операндом (справа от оператора). Исходное значение первого операнда при этом не меняется. Младшие биты теряются, а старшие заполняются нулями
&= Упрощенная форма побито- вого оператора & с присваиванием Команда вида A& A=A&B
|= Упрощенная форма побито- вого оператора | с присваиванием Команда вида A|=B является эквивалентом команды A=A|B

Оператор Название Пояснение
^= Упрощенная Команда вида A^=B является эквивалентом команды
форма побито-
вого оператора ^ A=A^B
с присваиванием
>>= Упрощенная Команда вида A>>=B является эквивалентом команды
форма побитово-
го оператора >> A=A>>B
с присваиванием
<<= Упрощенная Команда вида A<<=B является эквивалентом команды
форма побитово-
го оператора << A=A<
с присваиванием
>>>= Упрощенная Команда вида A>>>=B является эквивалентом команды
форма побитово-
го оператора >>> A=A>>>B
с присваиванием

За редким исключением, побитовые операции используются в случаях, когда необходимо оптимизировать программу в отношении быстродействия.

Помимо перечисленных операторов, в Java есть единственный тернарный опе- ратор (у оператора три операнда). Формально оператор обозначается как?:. Синтаксис вызова этого оператора следующий:

условие?значение_1:значение_2

Первым операндом указывается условие - выражение, возвращающее в качестве значения логическое значение. Если значение выражения-условия равно true, в качестве значения тернарным оператором возвращается значение_1. Если зна- чением выражения-условия является false, тернарным оператором в качестве значения возвращается значение_2.

Несколько замечаний по поводу оператора присваивания (оператор =). В Java оператор присваивания возвращает значение. Команда вида x=y выполняется следующим образом. Сначала вычисляется выражение y, после чего это выра- жение приводится к типу переменной x и затем записывается в эту переменную. Благодаря тому, что, в отличие от других операторов с равными приоритетами, присваивание выполняется справа налево, в Java допустимыми являются ко- манды вида x=y=z. В этом случае значение переменной z присваивается сначала переменной y, а затем значение переменной y присваивается переменной x.

Еще одно замечание касается упрощенных форм операторов с присваиванием, то есть операторов вида op=. Хотя утверждалось, что команда вида A op=B эк- вивалента команде A=A op B, это не совсем так. При выполнении команды вида A op=B сначала вычисляется выражение A op B, затем полученное значение при- водится к типу переменной A и только после этого присваивается переменной A. Поскольку приведение к типу переменной A выполняется, фактически, явно, а в команде A=A op B приведение типов неявное, может проявиться разница


в использовании полной и упрощенной форм команд присваивания. Рассмо- трим простой пример:

// Правильно: a+=20;

// Неправильно: a=a+b;

В данном случае команда a+=20 является корректной, а команда a=a+b - нет. В первом случае литерал 20 типа int «насильственно» приводится к типу byte в силу особенностей оператора +=. Во втором случае результат вычисления вы- ражения a+b автоматически расширяется до типа int, а автоматическое приведе- ние типа int к типу byte запрещено.

Напоследок приведем в табл. 1.6 данные о приоритете различных операторов в Java.

Таблица 1.6. Приоритеты операторов в Java

Приоритет Операторы
Круглые скобки (), квадратные скобки и оператор «точка»
Инкремент ++, декремент --, отрицания ~ и!
Умножение *, деление / и вычисление остатка %
Сложение + и вычитание -
Побитовые сдвиги >>, << и >>>
Больше >, больше или равно >=, меньше или равно <= и меньше <
Равно == и неравно!=
Побитовое И &
Побитовое исключающее ИЛИ ^
Побитовое ИЛИ |
Логическое И &&
Логические ИЛИ ||
Тернарный оператор?:
Присваивание = и сокращенные формы операторов вида op=

Операторы равных приоритетов (за исключением присваивания) выполняются слева направо. В случаях когда возникают сомнения в приоритете операторов и последовательности вычисления выражений, рекомендуется использовать круглые скобки.

Сдвиг вправо без учета знака

Как было показано, при каждом выполнении операция » автоматически заполняет старший бит его предыдущим содержимым. В результате знак значения сохраняется. Однако иногда это нежелательно. Например, при выполнении сдвига вправо в каком-либо значении, которое не является числовым, использование дополнительных знаковых разрядов может быть нежелательным. Эта ситуация часто встречается при работе со значениями пикселей и графическими изображениями. Как правило, в этих случаях требуется сдвиг нуля в позицию старшего бита независимо от его первоначального значения. Такое действие называют сдвигом вправо без учета знака. Для его выполнения используют операцию сдвига вправо без учета знака Java, >>>, которая всегда вставляет ноль в позицию старшего бита.

Следующий фрагмент кода демонстрирует применение операции >>>. В этом примере значение переменной а установлено равным -1, все 32 бита двоичного представления которого равны 1. Затем в этом значении выполняется сдвиг вправо на 24 бита с заполнением старших 24 битов нулями и игнорированием обычно используемых дополнительных знаковых разрядов. В результате значение а становится равным 255.

int а = -1;
а = а >>> 24;

Часто операция >>> не столь полезна, как хотелось бы, поскольку она имеет смысл только для 32- и 64-разрядных значений. Помните, что в выражениях тип меньших значений автоматически повышается до int. Это означает применение дополнительных знаковых разрядов и выполнение сдвига по отношению к 32-разрядным, а не 8- или 16-разрядным значениям. То есть программист может подразумевать выполнение сдвига вправо без учета знака применительно к значению типа byte и заполнение нулями, начиная с бита 7.

Однако в действительности это не так, поскольку фактически сдвиг будет выполняться в 32-разрядном значении. Этот эффект демонстрирует следующая программа.

// Сдвиг без учета знака значения типа byte.
class ByteUShift {
static public void main(String args) {
char hex = {
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
byte b = (byte) 0xfl;
byte с = (byte) (b » 4);
byte d = (byte) (b >» 4) ;
byte e = (byte) ((b & 0xff) » 4) ;
System.out.println (" b = 0x" + hex [ (b » 4) & 0x0f] + hex ) ;
System, out .println (" b » 4 = 0x" + hex[ (c » 4) & 0x0f] + hex) ;
System, out .println (" b »> 4 = 0x" + hex[ (d » 4) & 0x0f] + hex) ;
System.out.println(" (b & 0xff) » 4 = 0x" + hex[(e » 4) S 0x0f] + hex) ;
}
}

Из следующего вывода этой программы видно, что операция »> не выполняет никаких действий по отношению к значениям типа byte. Для этого примера в качестве значения переменной b было выбрано произвольное отрицательное значение типа byte. Затем переменной с присваивается значение переменной b типа byte, сдвинутое вправо на четыре позиции:, которое в связи с применением дополнительных знаковых разрядов равно Oxff. Затем переменной d присваивается значение переменной b типа byte, сдвинутое вправо на четыре позиции без учета знака, которым должно было бы быть значение OxOf, но в действительности, из-за применения дополнительных знаковых разрядов во время повышения типа b до int перед выполнением сдвига, равное Oxff. Последнее выражение устанавливает значение переменной е равным значению типа byte переменной Ь, замаскированному до 8 бит с помощью операции AND и затем сдвинутому вправо на четыре позиции, что дает ожидаемое значение, равное OxOf. Обратите внимание, что операция сдвига вправо без учета знака не применялась к переменной d, поскольку состояние знакового бита после выполнения операции AND было известно.

Побитовые составные операции с присваиванием

Подобно алгебраическим операциям, все двоичные побитовые операции имеют составную форму, которая объединяет побитовую операцию с операцией присваивания. Например, следующие два оператора, выполняющие сдвиг вправо на четыре позиции в значении переменной а, эквивалентны:

Аналогично, эквивалентны и следующие два оператора, которые присваивают переменной а результат выполнения побитовой операции a OR b:

а = а | b;
а |= b;

Следующая программа создает несколько целочисленных переменных, а затем использует составные побитовые операции с присваиванием для манипулирования этими переменными:

class OpBitEquals public static void main(String args){ int a = 1;
int b = 2;
int c = 3;
a |= 4;
b >= 1;
c a ^= c;
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("c = " + c);
}
}

Эта программа создает следующий вывод.



Загрузка...