Сайт о телевидении

Сайт о телевидении

» » Основные операторы Java. Беззнаковая арифметика в Java

Основные операторы Java. Беззнаковая арифметика в Java

Большинство операций над примитивными типами выполняется не с помощью методов, а с помощью специальных символов, называемых знаком операции .

Операция присваивания

Присвоение переменной значения константы, другой переменной или выражения (переменных и/или констант, разделенных знаками операций), называется операцией присваивания и обозначается знаком "= ", например: x = 3 ; y = x; z = x; В Java допустимо многократное использование операции присваивания в одном выражении, например: x1 = x2 = x3 = 0 ; Эта операция выполняется справа налево, т.е. сначала переменной x3 присваивается значение 0 , затем переменной x2 присваивается значение переменной x3 (0), и, наконец, переменной x1 присваивается значение переменной x2 (0). Знаки операций, аргументами которых являются числа, разделяются на две категории: унарные (unary) знаки операций с одним аргументом и бинарные (binary) с двумя аргументами.

Унарные операции

В Java определены следующие унарные операции:
  • унарный минус " - " – меняет знак числа или выражения на противоположный;
  • унарный плюс " + " – не выполняет никаких действий над числом или выражением;
  • побитовое дополнение " ~ " (только для целых) – инвертирует все биты поля числа (меняет 0 на 1 и 1 на 0);
  • инкремент " ++ " (только для целых) – увеличивает значение переменной на 1;
  • декремент " -- " (только для целых) – уменьшает значение переменной на 1.
Примеры унарных операций " + " и " - ": int i = 3 , j, k; j= - i; // j = -3 k = + i; // k = 3 Пример операции побитового дополнения: int a = 15 ; int b; b = ~ a; // b = -16 Числа a и b являются числами типа int , т.е. представляются внутри компьютера как двоичные целые числа со знаком длиной 32 бита, поэтому двоичное представление чисел a и b будет выглядеть следующим образом: a = 00000000 00000000 00000000 00001111 b = 11111111 11111111 11111111 11110000 Как видно из этого представления, все нулевые биты в числе a изменены на единичные биты в числе b , а единичные биты в a изменены на нулевые биты. Десятичным представлением числа b будет –16 . Знаки операции инкремента и декремента могут размещаться как до, так и после переменной. Эти варианты называются соответственно префиксной и постфиксной записью этих операции. Знак операции в префиксной записи возвращает значение своего операнда после вычисления выражения. При постфиксной записи знак операции сначала воз­вращает значение своего операнда и только после этого вычисляет инкремент или декремент, например: int x = 1 , y, z; y = ++ x; z= x++ ; Переменная y будет присвоено значение 2 , поскольку сначала значение x будет увеличено на 1 , а затем результат будет присвоен переменной y . Переменной z будет присвоено значение 1 , поскольку сначала переменной z будет присвоено значение, а затем значение x будет увеличено на 1 . В обоих случаях новое значение переменной x будет равно 2 . Следует отметить, что в Java, в отличие от языка C, операции декремента и инкремента могут применяться и к вещественным переменным (типа float и double). Бинарные знаки операций подразделяются на операции с числовым результатом и операции сравнения, результатом которых является булевское значение.

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

В Java определены следующие арифметические бинарные операции :
  • сложение " + ";
  • вычитание " - ";
  • умножение " * ";
  • деление " / ";
  • вычисление остатка от деления целых чисел " % " (возвращает остаток от деления первого числа на второе, причем результат будет иметь тот же знак, что и делимое), например, результат операции 5%3 будет равен 2 , а результат операции (-7)%(-4) будет равен -3 . В Java операция может использоваться и для вещественных переменных (типа float или double).
Примеры бинарных арифметических операций: int x = 7 , x1, x2, x3, x4, x5; x1 = x + 10 ; // x1 = 17 x2 = x – 8 ; // x2 = -1 x3 = x2 * x; // x3 = -7 x4 = x/ 4 ; // x4 = 1 (при делении целых чисел // дробная часть отбрасывается) x5 = x% 4 // x5 = 3 (остаток от деления // 7 на 4)

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

  • Побитовые операции рассматривают исходные числовые значения как поля битов и выполняют над ними следующие действия:
  • установка бита в i -ой позиции поля результата в 1 , если оба бита в i -ых позициях операндов равны 1 , или в 0 в противном случае – побитовое И (" & ");
  • установка бита в i -ой позиции поля результата в 1 , если хотя бы один бит в i -ых позициях операндов равен 1 , или в 0 в противном случае – побитовое ИЛИ (" | ");
  • установка бита в i -ой позиции поля результата в 1 , если биты в i -ых позициях операндов не равны друг другу, или в 0 в противном случае – побитовое исключающее ИЛИ (" ^ ");
  • сдвиг влево битов поля первого операнда на количество битов, определяемое вторым операндом (бит знака числа при этом не меняется) – побитовый сдвиг влево с учетом знака " << ";
  • сдвиг вправо битов поля первого операнда на количество битов, определяемое вторым операндом (бит знака числа при этом не меняется) – побитовый сдвиг вправо с учетом знака " >> ";
  • сдвиг вправо битов поля первого операнда на количество битов, определяемое вторым операндом (бит знака числа при этом также сдвигается) – побитовый сдвиг вправо без учета знака " >>> ".
Примеры побитовых операций:
  1. Побитовое И

    int x = 112 ; int y = 94 ; int z; z = x & y; // z=80: 00000000 00000000 00000000 01010000
  2. Побитовое ИЛИ

    int x = 112 ; // x: 00000000 00000000 00000000 01110000 int y = 94 ; // y: 00000000 00000000 00000000 01011110 int z; z = x | y; // z = 126: 00000000 00000000 00000000 01111110
  3. Побитовое исключающее ИЛИ

    int x = 112 ; // x: 00000000 00000000 00000000 01110000 int y = 94 ; // y: 00000000 00000000 00000000 01011110 int z; z = x ^ y; // z = 46: 00000000 00000000 00000000 00101110
  4. Сдвиг влево с учетом знака

    int x = 31 , z; // x: 00000000 00000000 00000000 00011111 z = x << 2 ; // z = 124: 00000000 00000000 00000000 01111100
  5. Сдвиг вправо с учетом знака

    int x = - 17 , z; z = x >> 2 ; // z = -5: 11111111 11111111 11111111 11111011
  6. Сдвиг вправо без учета знака

    int x = - 17 , z; // x: 11111111 11111111 11111111 11101111 z = x >>> 2 ; // z = 1073741819 // z: 00111111 11111111 11111111 11111011

Комбинированные операции

В Java для бинарных арифметических операций можно использовать комбинированные (составные) знаки операций: идентификатор операция = выражение Это эквивалентно следующей операции: идентификатор = идентификатор операция выражение Примеры:
  1. Выражение x += b означает x = x + b .
  2. Выражение x -= b означает x = x - b .
  3. Выражение x *= b означает x = x * b .
  4. Выражение x /= b означает x = x / b .
  5. Выражение x %= b означает x = x % b .
  6. Выражение x &= b означает x = x & b .
  7. Выражение x |= b означает x = x | b .
  8. Выражение x ^= b означает x = x ^ b .
  9. Выражение x <<= b означает x = x << b .
  10. Выражение x >>= b означает x = x >> b .
  11. Выражение x >>>= b означает x = x >>> b .

Операции сравнения

В Java определены следующие операции сравнения:
  • " == " (равно), " != " (не равно),
  • " > " (больше), " >= " (больше или равно),
  • " < " (меньше) " <= " (меньше или равно)
имеют два операнда и возвращают булевское значение, соответствующее результату сравнения (false или true ). Следует обратить внимание, что при сравнении двух величин на равенство в Java, как и в C и в C++, используются символы "== " (два идущих без пробела друг за другом знака равенства), в отличие от оператора присваивания, в котором используется символ "= ". Использование символа " = " при сравнении двух величин либо вызывает ошибку при компиляции, либо приводит к неверному результату. Примеры операций сравнения: boolean isEqual, isNonEqual, isGreater, isGreaterOrEqual, isLess, isLessOrEqual; int x1 = 5 , x2 = 5 , x3 = 3 , x4 = 7 ; isEqual = x1 == x2; // isEqual = true isNonEqual = x1 != x2; // isNonEqual = false isGreater = x1 > x3; // isGreater = true // isGreaterOrEqual = true isGreaterOrEqual = x2 >= x3; isLess = x3 < x1; // isLess = true isLessOrEqual = x1 <= x3; // isLessOrEqual = false

Булевские операции

Булевские операции выполняются над булевскими переменными и их результатом также является значение типа boolean . В Java определены следующие булевские операции:
  • отрицание "!" – замена false на true , или наоборот;
  • операция И "&" – результат равен true , только, если оба операнда равны true , иначе результат – false ;
  • операция ИЛИ " | " – результат равен true , только, если хотя бы один из операндов равен true , иначе результат – false .
  • операция исключающее ИЛИ " ^ " – результат равен true , только, если операнды не равны друг другу, иначе результат – false .
Операции " & ", " | " и " ^ " можно, также как и соответствующие побитовые операции использовать в составных операциях присваивания: " &= ", " |= " и " ^= " Кроме того, к булевским операндам применимы операции " == " (равно) и " != " (не равно). Как видно из определения операций ИЛИ и И, операция ИЛИ приводит к результату true , когда первый операнд равен true , незави­симо от значения второго операнда, а операция И приводит к результату false , когда первый операнд равен false , независимо от значения второго операнда. В Java определены еще две булевские операции: вторые версии булевских операций И и ИЛИ, известные как укороченные (short-circuit) логические операции: укороченное И " && " и укороченное ИЛИ " || ". При использовании этих операций второй операнд вообще не будет вычисляться, что полезно в тех случаях, когда правильное функционирование правого операнда зависит от того, имеет ли левый операнд значение true или false . Примеры булевских операций: boolean isInRange, isValid, isNotValid, isEqual, isNotEqual; int x = 8 ; isInRange = x > 0 && x < 5 ; // isInRange = false isValid = x > 0 || x > 5 ; // isValid = true isNotValid = ! isValid; // isNotValid = false isEqual = isInRange == isValid; // isEqual = false // isNotEqual = true isNotEqual = isInRange != isValid

Условная операция

Условная операция записывается в форме выражение-1?выражение-2:выражение-3 . При этом сначала вычисляется выражение выражение-1 , которое должно дать булевское значение, а затем, если выражение-1 имеет значение true , вычисляется и возвращается выражение-2 как результат выполнения операции, либо (если выражение-1 имеет значение false), вычисляется и, как результат выполнения операции, возвращается выражение-3 . Пример условной операции: x= n> 1 ? 0 : 1 ; Переменной x будет присвоено значение 0 , если n>1 (выражение n>1 имеет значение true) или 1 , если n≤1 (выражение n>1 имеет значение false).

Старшинство операций

Операции в выражениях выполняются слева направо, однако, в соответствии со своим приоритетом. Так операции умножения в выражении y = x + z* 5 ; будет выполнена раньше, чем операция сложения, поскольку приоритет операции умножения выше, чем приоритет операции сложения. Приоритеты операций (в порядке уменьшения приоритета) в Java приведены в табл. 1.
Круглые скобки повышают старшинство операций, которые находятся внутри них. Так, если в приведенное выше выражение вставить скобки: y = (x + z) * 5 ; то сначала будет выполнена операция сложения, а затем операция умножения. Иногда скобки используют просто для того, чтобы сделать выражение более читаемым, например: (x > 1 ) && (x <= 5 ) ;

Преобразование и приведение типов при выполнении операций

В операции присваивания и арифметических выражениях могут использоваться литералы, переменные и выражения разных типов, например: double y; byte x; y = x + 5 ; В этом примере выполняется операция сложения переменной x типа byte и литерала 5 (типа int) и результат присваивается переменной y типа double . В Java, как и в языке C, преобразования типов при вычислении выражений могут выполняться автоматически, либо с помощью оператора приведения типа. Однако правила приведения типов несколько отличаются от правил языка C, и в целом являются более строгими, чем в языке C. При выполнении операции присваивания преобразование типов происходит автоматически, если происходит расширяющее преобразование (widening conversion) и два типа совместимы . Расширяющими преобразованиями являются преобразования byte ®short ®int ®long ®float ®double . Для расширяющих преобразований числовые типы, включая целый и с пла­вающей точкой, являются совместимыми друг с другом. Однако числовые типы не совместимы с типами char и boolean . Типы char и boolean не совмес­тимы также и друг с другом. В языке Java выполняется автоматическое преобразование типов также и при сохранении литеральной целочисленной константы (которая имеет по умолчанию тип int) в перемен­ных типа byte , short или long (однако если литерал имеет значение вне диапазона допустимых значений для данного типа, выдается сообщение об ошибке: возможная потеря точности). Если преобразование является сужающим (narrowing conversion), т. е. выполняется преобразование byte ¬ short ¬ char ¬ int ¬ long ¬ float ¬ double , то такое преобразование может привести к потере точности числа или к его искажению. Поэтому при сужающих преобразованиях при компиляции программы выводится диагностическое сообщение о несовместимости типов и файлы классов не создаются. Такое сообщение будет выдано и при попытке преобразование выражений типа byte или short в переменную типа char . Если все же необходимо выполнить такие преобразования, используется операция приведения (cast) типа, которая имеет следующий формат: (тип-преобразования ) значение , где тип-преобразования определяет тип, в который необходимо преобразовать заданное значение , например, в результате выполнения операторов: byte x = 71 ; char symbol = (char ) x; переменная symbol получит значение " G ". Если значение с плавающей точкой присваивается целому типу, то (если значение с плавающей точкой имеет дробную часть) при явном преобразовании типа происходит также усечение (truncation) числа. Так, в результате выполнения оператора int x = (int ) 77.85 ; переменная x получит значение 77 . Если же присваиваемое значение лежит вне диапазона типа-преобразования , то результатом преобразования будет остаток от деления значения на модуль диапазона присваиваемого типа (для чисел типа byte модуль диапазона будет равен 256 , для short – 65536 , для int – 4294967296 и для long – 18446744073709551616). Например, в результате выполнения оператора byte x = (byte ) 514 ; переменная x получит значение 2 . При преобразовании целых или вещественных чисел в данные типа char , преобразование в символ происходит, если исходное число лежит в диапазоне от 0 до 127, иначе символ получает значение " ? ". При выполнении арифметических и побитовых преобразований все значения byte и short , а также char расширяются до int , (при этом в вычислениях для char используется числовое значение кода символа) затем, если хотя бы один операнд имеет тип long , тип целого выражения расширяется до long . Если один из операндов имеет тип float , то тип полного вы­ражения расширяется до float , а если один из операндов имеет тип double , то тип результата будет double . Так, если объявлены переменные byte a, c; short b; то в выражении a + b* c – 15 L + 1.5F + 1.08 - 10 ; сначала, перед вычислением a + b*c значения переменных будут расширены до int , затем, поскольку константа 15 имеет тип long , перед вычитанием результат вычисления будет увеличен до long . После этого, поскольку литерал 1.5 имеет тип float перед сложением с этим литералом результат вычисления a + b*c – 15L будет расширен до float . Перед выполнением сложения с числом 1.08 результат предыдущих вычислений будет расширен до double (поскольку вещественные константы по умолчанию имеют тип double) и, наконец, перед выполнением последнего сложения литерал 10 (по умолчанию int) будет расширен до double . Таким образом, результат вычисления выражения будет иметь тип double . Автоматические расширения типов (особенно расширения short и byte до int) могут вызывать плохо распознаваемые ошибки во время компиляции. Например, в операторах: byte x = 30 , y = 5 ; x = x + y; перед выполнением сложения значение переменных x и y будет расширено до int , а затем при выполнении попытки присвоения результата вычисления типа int переменной типа byte будет выдано сообщение об ошибке. Чтобы этого избежать надо использовать во втором операторе явное преобразование типов: x = (byte ) (x + y) ; Выражение x + y необходимо заключит в скобки потому, что приоритет операции приведения типа, заключенной в скобки, выше, чем приоритет операции сложения. Кстати, если записать второй оператор в виде: x += y; то сообщения об ошибке не будет. Ссылка на перво

Тебе наверняка знакомо слово “бит”. Если же нет, давай познакомимся с ним:) Бит - минимальная единица измерения информации в компьютере. Его название происходит от английского “binary digit ” - “двоичное число”. Бит может быть выражен одним из двух чисел: 1 или 0. Существует специальная система счисления, основанная на единицах и нулях - двоичная .

Не будем углубляться в дебри математики и отметим лишь, что любое число в Java можно сконвертировать в его двоичную форму. Для этого нужно использовать классы-обертки. Например, вот как можно сделать это для числа int: public class Main { public static void main (String args) { int x = 342 ; System. out. println (Integer. toBinaryString (x) ) ; } } Вывод в консоль: 101010110 1010 10110 (я добавил пробел для удобства чтения) - это число 342 в двоичной системе. Мы фактически разделили это число на отдельные биты - нули и единицы. Именно с ними мы можем выполнять операции, которые называются побитовыми.

    ~ - побитовый оператор “НЕ”.

Он работает очень просто: проходится по каждому биту нашего числа и меняет его значение на противоположное: нули - на единицы, единицы - на нули. Если мы применим его к нашему числу 342, вот что получится: 101010110 - число 342 в двоичной системe 010101001 - результат выражения ~342 Попробуем выполнить это на практике: public class Main { public static void main (String args) { int x = 342 ; System. out. println (~ x) ; } } Вывод в консоль: -343 -343 - это наш результат (число 010101001) в привычной десятичной системе:)

    & - побитовый оператор “И”

Он, как видишь, довольно похож по написанию на логический “И” (&&). Оператор && , как ты помнишь, возвращает true только если оба операнда являются истинными. Побитовый & работает схожим образом: он сравнивает два числа по битам. Результатом этого сравнения является третье число. Для примера, возьмем числа 277 и 432: 100010101 - число 277 в двоичной форме 110110000 - число 432 в двоичной форме Далее оператор & сравнивает первый бит верхнего числа с первым битом нижнего. Поскольку это оператор “И”, то результат будет равен 1 только в том случае, если оба бита равны 1. Во всех остальных случаях результатом будет 0. 100010101 & 110110000 _______________ 100010000 - результат работы & Мы сравниваем сначала первые биты двух чисел друг с другом, потом вторые биты, третьи и т.д. Как видишь, только в двух случаях оба бита в числах были равны 1 (первый и пятый по счету биты). Результатом всех остальных сравнений стал 0. Поэтому в итоге у нас получилось число 100010000. В десятичной системе ему соответствует число 272. Давай проверим: public class Main { public static void main (String args) { System. out. println (277 & 432 ) ; } } Вывод в консоль: 272
  • | - побитовое “ИЛИ”. Принцип работы тот же - сравниваем два числа по битам. Только теперь если хотя бы один из битов равен 1, результат будет равен 1. Посмотрим на тех же числах - 277 и 432:
100010101 | 110110000 _______________ 110110101 - результат работы | Здесь уже результат другой: нулями остались только те биты, которые в обоих числах были нулями. Результат работы - число 110110101. В десятичной системе ему соответствует число 437. Проверим: public class Main { public static void main (String args) { System. out. println (277 | 432 ) ; } } Вывод в консоль: 437 Мы все посчитали верно! :)
  • ^ - побитовое исключающее “ИЛИ” (также известно как XOR)
С таким оператором мы еще не сталкивались. Но ничего сложного в нем нет. Он похож на обычное “или”. Разница в одном: обычное “или” возвращает true , если хотя бы один операнд является истинным. Но не обязательно один - если оба будут true - то и результат true . А вот исключающее “или” возвращает true только если один из операндов является истинным. Если истинны оба операнда , обычное “или” вернет true (“хотя бы один истинный“), а вот исключающее или вернет false . Поэтому он и называется исключающим. Зная принцип предыдущих побитовых операций, ты наверняка и сам сможешь легко выполнить операцию 277^432. Но давай лучше лишний раз разберемся вместе:) 100010101 ^ 110110000 _______________ 010100101 - результат работы ^ Вот и наш результат. Те биты, которые были в обоих числах одинаковыми, вернули 0 (не сработала формула “один из”). А вот те, которые образовывали пару 0-1 или 1-0, в итоге превратились в единицу. В результате мы получили число 010100101. В десятичной системе ему соответствует число 165. Давай посмотрим, правильно ли мы посчитали: public class Main { public static void main (String args) { System. out. println (277 ^ 432 ) ; } } Вывод в консоль: 165 Супер! Все именно так, как мы и думали:) Теперь самое время познакомиться с операциями, которые называют битовыми сдвигами . Название, в принципе, говорит само за себя. Мы возьмем какое-то число и будем двигать его биты влево и вправо:) Давай посмотрим как это выглядит:

Сдвиг влево

Сдвиг битов влево обозначается знаком << Пример: public class Main { public static void main (String args) { int x = 64 ; //значение int y = 3 ; //количество int z = (x << y) ; System. out. println (Integer. toBinaryString (x) ) ; System. out. println (Integer. toBinaryString (z) ) ; } } В этом примере число x=64 называется значением . Именно его биты мы будем сдвигать. Сдвигать биты мы будем влево (это можно определить по направлению знака <<) В двоичной системе число 64 = 1000000 Число y=3 называется количеством . Количество отвечает на вопрос “на сколько бит вправо/влево нужно сдвинуть биты числа x ” В нашем примере мы будем сдвигать их на 3 бита влево. Чтобы процесс сдвига был более понятен, посмотрим на картинке. У нас в примере используются числа типа int. Int ’ы занимают в памяти компьютера 32 бита. Вот так выглядит наше изначальное число 64:

А теперь мы, в прямом смысле слова, берем каждый из наших битов и сдвигаем влево на 3 ячейки:

Вот что у нас получилось. Как видишь, все наши биты сдвинулись, а из-за пределов диапазона добавились еще 3 нуля. 3 - потому что мы делали сдвиг на 3. Если бы мы сдвигали на 10, добавилось бы 10 нулей. Таким образом, выражение x << y означает “сдвинуть биты числа х на y ячеек влево”. Результатом нашего выражения стало число 1000000000, которое в десятичной системе равно 512. Проверим: public class Main { public static void main (String args) { int x = 64 ; //значение int y = 3 ; //количество int z = (x << y) ; System. out. println (z) ; } } Вывод в консоль: 512 Все верно! Теоретически, биты можно сдвигать до бесконечности. Но поскольку у нас число int , в распоряжении есть всего 32 ячейки. Из них 7 уже заняты числом 64 (1000000). Поэтому если мы сделаем, например, 27 сдвигов влево, наша единственная единица выйдет за пределы диапазона и “затрётся”. Останутся только нули! public class Main { public static void main (String args) { int x = 64 ; //значение int y = 26 ; //количество int z = (x << y) ; System. out. println (z) ; } } Вывод в консоль: 0 Как мы и предполагали, единичка вышла за пределы 32 ячеек-битов и исчезла. У нас получилось 32-битное число, состоящее из одних нулей.

Естественно, в десятичной системе ему соответствует 0. Простое правило для запоминания сдвигов влево: При каждом сдвиге влево выполняется умножение числа на 2. Например, попробуем без картинок с битами посчитать результат выражения 111111111 << 3 Нам нужно трижды умножить число 111111111 на 2. В результате у нас получается 888888888. Давай напишем код и проверим: public class Main { public static void main (String args) { System. out. println (111111111 << 3 ) ; } } Вывод в консоль: 888888888

Сдвиги вправо

Они обозначаются знаком >> . Делают то же самое, только в другую сторону! :) Не будем изобретать велосипед и попробуем сделать это с тем же числом int 64. public class Main { public static void main (String args) { int x = 64 ; //значение int y = 2 ; //количество int z = (x >> y) ; System. out. println (z) ; } }

В результате сдвига на 2 вправо два крайних нуля нашего числа вышли за пределы диапазона и затерлись. У нас получилось число 10000, которому в десятичной системе соответствует число 16 Вывод в консоль: 16 Простое правило для запоминания сдвигов вправо: При каждом сдвиге вправо выполняется деление на два с отбрасыванием любого остатка. Например, 35 >> 2 означает, что нам нужно 2 раза разделить 35 на 2, отбрасывая остатки 35/2 = 17 (отбросили остаток 1) 17:2 = 8 (отбросили остаток 1) Итого, 35 >> 2 должно быть равно 8. Проверяем: public class Main { public static void main (String args) { System. out. println (35 >> 2 ) ; } } Вывод в консоль: 8

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

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

Operator Precedence

Operators Precedence
postfix expr++ expr--
unary ++expr --expr +expr ~ !
Multiplicative * / %
additive + -
shift << >> >>>
relational < > <= >= instanceof
equality == !=
bitwise AND &
bitwise exclusive OR ^
bitwise inclusive OR |
logical AND &&
logical OR ||
ternary ? :
assignment = += -= *= /= %= &= ^= |= <<= >>= >>>=
Все операции выполняются слева направо , однако с учетом своего приоритета. Например, если мы пишем: int x = 6 - 4/2; вначале будет выполнена операция деления (4/2). Хоть она и идет второй по счету, но у нее выше приоритет . Круглые или квадратные скобки меняют любой приоритет на максимальный. Это ты наверняка помнишь еще со школы. Например, если добавить их к выражению: int x = (6 - 4)/2; первым выполнится именно вычитание, поскольку оно вычисляется в скобках. У логического оператора && приоритет довольно низкий, что видно из таблицы. Поэтому чаще всего он будет выполняться последним. Например: boolean x = 6 - 4/2 > 3 && 12*12 <= 119; Это выражение будет выполняться так:
  • boolean x = 6 - 2 > 3 && 12 * 12 <= 119 ;

  • 12*12 = 144

    boolean x = 6 - 2 > 3 && 144 <= 119 ;
  • boolean x = 4 > 3 && 144 <= 119 ;

  • 4 > 3 = true

    boolean x = true && 144 <= 119 ;

  • 144 <= 119 = false

    boolean x = true && false ;

  • И, наконец, последним, будет выполнен оператор “И” && .

    boolean x = true && false;
    boolean x = false;

    Оператор сложения (+), например, имеет более высокий приоритет, чем оператор сравнения!= (“не равно”);

    Поэтому в выражении:

    Boolean x = 7 != 6+1;

    сначала будет выполнена операция 6+1, потом проверка 7!=7 (false), а в конце - присваивания результата false переменной x . У присваивания вообще самый маленький приоритет из всех операций - посмотри в таблице.

Фух! Лекция у нас получилась большая, но ты справился! Если ты не до конца понял какие-то части этой и предыдущей лекций - не переживай, мы еще не раз коснемся данных тем в будущем. Вот тебе несколько полезных ссылок:
  • Отличная в картинках про побитовые операции


  • - лекция JavaRush о логических и числовых операциях. Мы до них еще нескоро дойдем, но почитать можно уже сейчас, вреда не будет

Как известно, в Java нет беззнаковых типов. Если в Си вы могли написать unsigned int (char , long), то в Java так не получится. Однако нередко возникает необходимость в выполнении арифметических операций именно с числами без знака. На первый взгляд кажется, что беззнаковые типы в принципе-то и не особо нужны (подумаешь, MaxInt для чисел со знаком меньше в два раза, если нужны числа больше, я просто возьму long и далее BigInteger). Но основное различие на самом деле не в том, сколько различных неотрицательных чисел можно положить в signed или unsigned int, а в том, как над ними производятся арифметические операции и сравнения. Если вы работаете с бинарными протоколами или с двоичной арифметикой, где важен каждый используемый бит, нужно уметь выполнять все основные операции в беззнаковом режиме. Рассмотрим эти операции по порядку:

Преобразование byte в short (int, long)

Обычный каст (int) myByte выполнит расширение до 32 бит со знаком - это означает, что если старший бит байта был установлен в 1, то результатом будет то же самое отрицательное число, но записанное в 32-битном формате:

0xff -> 0xffffffff (-1)

Часто это не то, чего бы мы хотели. Для того, чтобы выполнить расширение до 32 бит без знака и получить 0x000000ff , в Java можно записать:

Int myInt = myByte & 0xff; short myShort = myByte & 0xff;

Сравнение без учёта знака

Для беззнакового сравнения есть лаконичная формула:

Int compareUnsigned(int a, int b) { return Integer.compare(a ^ 0x80000000, b ^ 0x80000000); }
Для byte, short и long, соответственно, константы будут 0x80 , 0x8000 и 0x8000000000000000L .

Сложение, вычитание и умножение

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

Деление

Деление -256 на 256 даст нам -1. А нам бы хотелось, чтобы 0xffffff00 / 0x100 давало 0x00ffffff , а не 0xffffffff (-1) . Для byte , short и int решением будет переход к числам большей разрядности:

Int a = 0xffffff00; int b = 0x100; int c = (int) ((a & 0xffffffffL) / b); // convert a to long before division
Но что делать с long ? Переходить на BigInteger в таких случаях обычно не вариант - слишком медленно. Остаётся только брать всё в свои руки и реализовывать деление вручную. К счастью, всё уже украдено до нас - в Google Guava есть реализация беззнакового деления для long , причём довольно шустрая. Если вы не используете эту библиотеку, проще всего выдрать кусок кода прямо из файла :

/** * Returns dividend / divisor, where the dividend and divisor are treated as unsigned 64-bit * quantities. * * @param dividend the dividend (numerator) * @param divisor the divisor (denominator) * @throws ArithmeticException if divisor is 0 */ public static long divide(long dividend, long divisor) { if (divisor < 0) { // i.e., divisor >= 2^63: if (compare(dividend, divisor) < 0) { return 0; // dividend < divisor } else { return 1; // dividend >= divisor } } // Optimization - use signed division if dividend < 2^63 if (dividend >= 0) { return dividend / divisor; } /* * Otherwise, approximate the quotient, check, and correct if necessary. Our approximation is * guaranteed to be either exact or one less than the correct value. This follows from fact * that floor(floor(x)/i) == floor(x/i) for any real x and integer i != 0. The proof is not * quite trivial. */ long quotient = ((dividend >>> 1) / divisor) << 1; long rem = dividend - quotient * divisor; return quotient + (compare(rem, divisor) >= 0 ? 1: 0); }
Чтобы код компилировался, придётся также позаимствовать реализацию compare(long, long) :

/** * Compares the two specified {@code long} values, treating them as unsigned values between * {@code 0} and {@code 2^64 - 1} inclusive. * * @param a the first unsigned {@code long} to compare * @param b the second unsigned {@code long} to compare * @return a negative value if {@code a} is less than {@code b}; a positive value if {@code a} is * greater than {@code b}; or zero if they are equal */ public static int compare(long a, long b) { return Longs.compare(flip(a), flip(b)); }
и Longs.compare(long, long) + flip(long) :

/** * A (self-inverse) bijection which converts the ordering on unsigned longs to the ordering on * longs, that is, {@code a <= b} as unsigned longs if and only if {@code flip(a) <= flip(b)} * as signed longs. */ private static long flip(long a) { return a ^ Long.MIN_VALUE; } /** * Compares the two specified {@code long} values. The sign of the value * returned is the same as that of {@code ((Long) a).compareTo(b)}. * * @param a the first {@code long} to compare * @param b the second {@code long} to compare * @return a negative value if {@code a} is less than {@code b}; a positive * value if {@code a} is greater than {@code b}; or zero if they are equal */ public static int compare(long a, long b) { return (a < b) ? -1: ((a > b) ? 1: 0); }

Побитовые сдвиги

Чтобы окончательно покрыть тему о битовых операциях, вспомним также о сдвигах. В x86 ассемблере есть целая пачка различных команд, которые делают побитовые сдвиги - SHL, SHR, SAL, SAR, ROR, ROL, RCR, RCL. Последние 4 осуществляют циклические сдвиги, их эквивалентов в Java нет. А вот логические и арифметические сдвиги присутствуют. Логический сдвиг (не учитывает знака) - SHL (shift left) и SHR (shift right) - реализуется в Java операторами << и >>> соответственно. С помощью логических сдвигов можно быстро выполнять целочисленные умножение и деление на числа степени двойки. Арифметический сдвиг (учитывает знак) вправо - SAR - реализуется оператором >> . Арифметический сдвиг влево эквивалентен логическому, и поэтому специального оператора для него нет. Может показаться странным, что в ассемблере есть специальный опкод для этой операции, но на самом деле он делает то же самое, то есть SAL полностью повторяет поведение SHL, и об этом прямо говорит документация от Intel:
The shift arithmetic left (SAL) and shift logical left (SHL) instructions perform the same operation; they shift the bits in the destination operand to the left (toward more significant bit locations). For each shift count, the most significant bit of the destination operand is shifted into the CF flag, and the least significant bit is cleared (see Figure 7-7 in the Intel®64 and IA-32 Architectures Software Developer"sManual, Volume 1).

То есть SAL добавили просто для симметрии, с учётом того, что для сдвига вправо есть разделение на логический и арифметический. Ну а Гослинг решил не заморачиваться (и, думается, правильно сделал).

Итак, мы имеем следующее:

A << 1; // беззнаковый сдвиг влево, эквивалентно умножению на 2 a >> 1; // сдвиг вправо с учётом знака (эквивалентно делению на 2) a >>> 1; // сдвиг вправо без учёта знака (эквивалентно беззнаковому делению на 2)

  • При выполнении арифметических действий, которые могут привести к переполнению в выбранной разрядной сетке, нужно всегда точно представлять, какая область допустимых значений может быть у переменных, и отслеживать эти инварианты, расставляя утверждения (assertions). Например, очевидно, что при умножении двух произвольных 32-разрядных беззнаковых чисел результат может не поместиться в 32 бита, и если вам нужно избежать переполнения, нужно либо убедиться, что в этом месте никогда не будет ситуации, при которой произведение не влезает в 32 бита, либо необходимо предварительно сконвертировать оба операнда в long (выполнив a & 0xffffffffL). Здесь, кстати, можно легко допустить ошибку, сконвертировав только один из операндов. Нет, нужно сконвертировать в long оба, т.к. если второй операнд окажется отрицательным, он будет неявно преобразован в long с расширением знака, и результат умножения будет неправильным.
  • Щедро расставляйте скобки в выражениях, где используются побитовые операции. Дело в том, что приоритет побитовых операторов в Java несколько странный, и часто ведёт себя неочевидным образом. Лучше добавить пару скобок, чем потом несколько часов искать трудноуловимые ошибки.
  • Если вам нужна константа типа long , не забудьте добавить суффикс L в конец литерала константы. Если этого не сделать, это будет не long , а int , и при неявном приведении к long снова произойдёт неприятное нам расширение со знаком.

Операторы в языке Java - это специальные символы, которые сообщают транслятору о том, что вы хотите выполнить операцию с не­которыми операндами. Некоторые операторы требуют одного операн­да, их называют унарными. Одни операторы ставятся перед операндами и называются пре­фиксными, другие - после, их называют постфиксными операторами. Большинство же операторов ставят между двумя операндами, такие операторы называют­ся инфиксными бинарными операторами. Существует тернарный опе­ратор, работающий с тремя операндами.

В Java имеется 44 встроенных оператора. Их можно разбить на 4 класса - арифметические, битовые, операторы сравнения и логические.

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

Арифметические операторы используются для вычислений так же как в алгебре (см. таблицу со сводкой арифметических операторов ниже). Допустимые операнды должны иметь числовые типы. Например, исполь­зовать эти операторы для работы с логическими типами нельзя, а для работы с типом char можно, поскольку в Java тип char - это подмно­жество типа int.

Оператор

Результат

Оператор

Результат

Сложение

сложение с присваиванием

вычитание (также унарный минус)

вычитание с присваиванием

Умножение

умножение с присваиванием

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

деление по модулю

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

Инкремент

декремент

Четыре арифметических действия

Ниже, в качестве примера, приведена простая программа, демонстрирующая использование операторов. Обратите внимание на то, что операторы работают как с целыми литерала­ми, так и с переменными.

class BasicMath{ public static void int a = 1 + 1;

intb = a *3;

main(String args) {

int c = b / 4;

int d = b - а;

int e = -d;

System.out.println("a =" +а);

System.out.println("b =" +b);

System.out.println("c =" +c);

System.out.println("d =" +d);

System.out.println("e =" +e);

} }

Исполнив эту программу, вы должны получить приведенный ниже ре­зультат:

C: \> java BasicMath

a = 2

b = 6

c = 1

d = 4

e = -4

Оператор деления по модулю

Оператор деления по модулю, или оператор mod, обозначается сим­волом %. Этот оператор возвращает остаток от деления первого операнда на второй. В отличие от C++, функция mod в Java работает не только с целыми, но и с вещественными типами. Приведенная ниже программа иллюстрирует работу этого оператора.

class Modulus {

public static void main (String args ) {

int x = 42;

double у = 42.3;

System.out.println("x mod 10 = " + x % 10);

System.out.println("y mod 10 = " + у % 10);

} }

Выполнив эту программу, вы получите следующий результат:

С:\> Modulus

x mod 10 = 2

y mod 10 = 2.3

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

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

class OpEquals {

int a = 1;

int b = 2;

int с = 3;

a += 5;

b *= 4;

c += a * b;

с %= 6;

} }

А вот и результат, полученный при запуске этой программы:

С:> Java OpEquals

а = 6

b = 8

с = 3

Инкремент и декремент

В С существует 2 оператора, называемых операторами инкремента и декремента (++ и --) и являющихся сокращенным вариантом записи для сложения или вычитания из операнда единицы. Эти операторы уникальны в том плане, что могут использоваться как в префиксной, так и в постфиксной форме. Следующий при­мер иллюстрирует использование операторов инкремента и декреме нта.

class IncDec {

public static void main(String args) {

int a = 1;

int b = 2;

int c = ++b;

int d = a++;

c++;

System.out.println("a = " + a);

System.out.println("b = " + b);

System.out.println("c = " + c);

} }

Результат выполнения данной программы будет таким:

C:\ java IncDec

a = 2

b = 3

c = 4

d = 1

Целочисленные битовые операторы

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

Оператор

Результат

Оператор

Результат

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

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

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

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

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

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

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

сдвиг вправо

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

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

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

сдвиг влево

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

Пример программы, манипулирующей с битами

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

class Bitlogic {

public static void main(String args ) {

String binary = { "OOOO", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001","1010", "1011", "1100", "1101",

"1110", "1111" };

int a = 3;//0+2+1или двоичное 0011

int b = 6;//4+2+0или двоичное 0110

int c = a | b;

int d = a & b;

int e = a ^ b;

int f = (~a & b) | (a & ~b);

int g = ~a & 0x0f;

System.out.println(" a = " + binary[a]);

System.out.println(" b = " + binary[b]);

System.out.println(" ab = " + binary[c]);

System.out.println(" a&b = " + binary[d]);

System.out.println(" a^b = " + binary[e]);

System.out.рrintln("~a&b|а^~Ь = " + binary[f]);

System.out.println(" ~a = " + binary[g]);

} }

Ниже при­веден результат, полученный при выполнении этой программы:

С: \> Java BitLogic

a = 0011

b = 0110

a | b = 0111

a & b = 0010

a ^ b = 0101

~a & b | a & ~b = 0101

~а = 1100

Сдвиги влево и вправо

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

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

В следующей программе байтовое значение преобразуется в строку, содержащую его шестнадцатиричное представление. Обратите внимание - сдвинутое значение приходится маскировать, то есть логически умножать на значение 0 х0 f, для того, чтобы очистить заполняемые в результате расширения знака биты и по­низить значение до пределов, допустимых при индексировании массива шестнадцатиричных цифр.

classHexByte {

char hex = { "0", "1, "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f };

byte b = (byte) 0xf1;

System.out.println(“b = 0x” + hex[(b >> 4) & 0x0f] + hex);

} }

Ниже приведен результат работы этой программы:

С:\> java HexByte

b = 0xf1

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

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

class ByteUShift{

static public void main(String args) {

char hex = { "0", "1’, "2", "3", "4","5", "6", "7", "8", "9", "а", "b", "с", "d","e", "f’ };

byte b = (byte) 0xf1;

byte c = (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) & 0x0f] + hex);

} }

Для этого примера переменную b можно было бы инициализировать произвольным отрицательным числом, мы использовали число с шест­надцатиричным представлением 0xf1. Переменной с присваивается ре­зультат знакового сдвига b вправо на 4 разряда. Как и ожидалось, рас­ширение знакового разряда приводит к тому, что 0xf1 превращается в 0xff. Затем в переменную d заносится результат беззнакового сдвига b вправо на 4 разряда. Можно было бы ожидать, что в результате d со­держит 0x0f, однако на деле мы снова получаем 0xff. Это - результат расширения знакового разряда, выполненного при автоматическом по­вышении типа переменной b до int перед операцией сдвига вправо. На­конец, в выражении для переменной е нам удается добиться желаемого результата - значения 0x0f. Для этого нам пришлось перед сдвигом вправо логически умножить значение переменной b на маску 0xff, очис­тив таким образом старшие разряды, заполненные при автоматическом повышении типа. Обратите внимание, что при этом уже нет необходи­мости использовать беззнаковый сдвиг вправо, поскольку мы знаем со­стояние знакового бита после операции AND.

С: \> java ByteUShift

b = 0xf1

b >> 4 = 0xff

b >>> 4 = 0xff

b & 0xff) >> 4 = 0x0f

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

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

class OpBitEquals {

public static void main(String args) {

int a = 1;

int b = 2;

int с = 3;

a |= 4;

b >>= 1;

с <<= 1;

а ^= с;

System.out.println("a = " + a);

System.out.println("b = " + b);

System.out.println("c = " + c);

} }

Результаты исполнения программы таковы:

С:\> Java OpBitEquals

а = 3

b = 1

с = 6

Операторы отношения

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

Оператор

Результат

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

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

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

Булевы логические операторы

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

Оператор

Результат

Оператор

Результат

логическое И (AND)

И (AND) с присваиванием

логическое ИЛИ (OR)

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

логическое исключающее ИЛИ (XOR)

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

оператор OR быстрой оценки выражений (short circuit OR)

оператор AND быстрой оценки выражений (short circuit AND)

логическое унарное отрицание (NOT)

тернарный оператор if-then-else

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

Программа, приведенная ниже, практически полностью повторяет ужезнакомый вам пример BitLogic. Только но на этот раз мы работаем с булевыми логическими значениями.

class BoolLogic {

public static void main(String args) {

boolean a = true;

boolean b = false;

boolean с = a | b;

boolean d = a & b;

boolean e = a ^ b;

boolean f = (!a & b) | (a & !b);

boolean g = !a;

System.out.println(" a = " + a);

System.out.println(" b = " + b);

System.out.println(" a|b = " + c);

System.out.println(" a&b = " + d);

System.out.println(" a^b = " + e);

System.out.println("!a&b|a&!b = " + f);

System.out.println(" !a = " + g);

} }

С: \> Java BoolLogic

а = true

b = false

a|b = true

a&b = false

a^b = true

!a&b|a&!b = true

!a = false

Операторы быстрой оценки логических выражений (short circuit logical operators)

Существуют два интересных дополнения к набору логических опера­торов. Это - альтернативные версии операторов AND и OR, служащие для быстрой оценки логических выражений. Вы знаете, что если первый операнд оператора OR имеет значение true, то независимо от значения второго операнда результатом операции будет величина true. Аналогично в случае оператора AND, если первый операнд - false, то значение вто­рого операнда на результат не влияет - он всегда будет равен false. Если вы в используете операторы && и || вместо обычных форм & и |, то Java не производит оценку правого операнда логического выражения, если ответ ясен из значения левого операнда. Общепринятой практикой является использование операторов && и || практически во всех случаях оценки булевых логических выражений. Версии этих операторов & и | применяются только в битовой арифметике.

Тернарный оператор if-then-else

Общая форма оператора if-then-use такова:

выражение1? выражение2: выражениеЗ

В качестве первого операнда - «выражение1» - может быть исполь­зовано любое выражение, результатом которого является значение типа boolean. Если результат равен true, то выполняется оператор, заданный вторым операндом, то есть, «выражение2». Если же первый операнд paвен false, то выполняется третий операнд - «выражениеЗ». Второй и третий операнды, то есть «выражение2» и «выражениеЗ», должны воз­вращать значения одного типа и не должны иметь тип void.

В приведенной ниже программе этот оператор используется для про­верки делителя перед выполнением операции деления. В случае нулевого делителя возвращается значение 0.

class Ternary {

public static void main(String args) {

int a = 42;

int b = 2;

int c = 99;

int d = 0;

int e = (b == 0) ? 0: (a / b);

int f = (d == 0) ? 0: (c / d);

System.out.println("a = " + a);

System.out.println("b = " + b);

System.out.println("c = " + c);

System.out.println("d = " + d);

System.out.println("a / b = " + e);

System.out.println("c / d = " + f);

} }

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

С: \>java Ternary

а = 42

b = 2

с = 99

d = 0

a / b = 21

с / d= 0

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

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

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

Явные приоритеты

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

а >> b + 3

Какому из двух выражений, а >> (b + 3) или (а >> b) + 3, соответствует первая строка? Поскольку у оператора сложения более высокий приоритет, чем у оператора сдвига, правильный ответ - а>> (b + а). Так что если вам требуется выполнить операцию (а>>b)+ 3 без скобок не обойтись.

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