Битовое представление числа java. Побитовые операции

Операторы в языке 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. Теперь вы можете сконструировать любое выражение с различными типами данных . В следующей главе познакомимся с конструкциями ветвления, организацией циклов и научимся управлять выполнением программы.

1. Основные арифметические операции

В следующей таблице перечислены основные арифметические операции, применяемые в языке Java:

Рассмотрим некоторые правила работы с арифметическими операциями:

  • Выражения вычисляются слева направо, если не добавлены круглые скобки или одни операции имеют более высокий приоритет.
  • Операции *, /, и % имеют более высокий приоритет чем + и -.

Пример 1. Арифметические операции над целочисленными значениями

Например, в этом коде, переменные a и b будут иметь разные значения:

Public class BasicIntMath { public static void main(String args) { int a = 4 + 5 - 2 * 3; int b = 4 + (5 - 2) * 3; System.out.println("a = " + a); System.out.println("b = " + b); } }

Результат выполнения:

A = 3 b = 13

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

Пример 2. Унарные операции сложения и вычитания

public class UnarySignOperation { public static void main(String args) { double a = -6; double b = +6; System.out.println(a); System.out.println(b); } }
  • Когда операция деления выполняется над целочисленным типом данных, ее результат не будет содержать дробный компонент.

Пример 3. Деление целочисленных чисел

public class IntDivision { public static void main(String args) { int a = 16 / 5; System.out.println(a); } }

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

  • Операнды арифметических операций должны иметь числовой тип. Арифметические операции нельзя выполнять над логическими типами данных, но допускается над типами данных char , поскольку в Java этот тип, по существу, является разновидностью типа int .

Пример 4. Арифметические операции над переменными типа char

public class BasicCharMath1 { public static void main(String args) { char c = "n"; System.out.println(c); System.out.println(c + 1); System.out.println(c / 5); } }

Результат выполнения:

N 111 22

Пример 5. Арифметические операции над переменными типа char

public class BasicCharMath2 { public static void main(String args) { char c1 = "1"; char c2 = "\u0031"; char c3 = 49; System.out.println(c1 + c2 + c3); } }

Результат выполнения:

    Оператор деления по модулю — обозначается символом %. Этот оператор возвращает остаток от деления первого числа на второй. При делении целого числа результатом будет тоже целое число.

Пример 6. Деление по модулю

public class DivisionByModule { public static void main(String args) { int a = 6 % 5; double b = 6.2 % 5.0; System.out.println(a); System.out.println(b); } }

Результат выполнения:

1 1.2000000000000002

2. Составные арифметические операции с присваиванием

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

А = а + 4;

B Java эту операцию можно записать следующим образом:

А += 4;

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

Пример 5. Составные арифметические операции с присваиванием

public class CompoundOperations { public static void main(String args) { int a = 1; int b = 2; int c = 3; a += 3; b *= 2; c += a * b; System.out.println(a); System.out.println(b); System.out.println(c); } }

Для целых числовых типов данных - 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 .

Последнее обновление: 30.10.2018

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

Каждое число имеет определенное двоичное представление. Например, число 4 в двоичной системе 100, а число 5 - 101 и так далее.

К примеру, возьмем следующие переменны:

Byte b = 7; // 0000 0111 short s = 7; // 0000 0000 0000 0111

Тип byte занимает 1 байт или 8 битов, соответственно представлен 8 разрядами. Поэтому значение переменной b в двоичном коде будет равно 00000111 . Тип short занимает в памяти 2 байта или 16 битов, поэтому число данного типа будет представлено 16 разрядами. И в данном случае переменная s в двоичной системе будет иметь значение 0000 0000 0000 0111 .

Для записи чисел со знаком в Java применяется дополнительный код (two’s complement), при котором старший разряд является знаковым. Если его значение равно 0, то число положительное, и его двоичное представление не отличается от представления беззнакового числа. Например, 0000 0001 в десятичной системе 1.

Если старший разряд равен 1, то мы имеем дело с отрицательным числом. Например, 1111 1111 в десятичной системе представляет -1. Соответственно, 1111 0011 представляет -13.

Логические операции

Логические операции над числами представляют поразрядные операции. В данном случае числа рассматриваются в двоичном представлении, например, 2 в двоичной системе равно 10 и имеет два разряда, число 7 - 111 и имеет три разряда.

    & (логическое умножение)

    Умножение производится поразрядно, и если у обоих операндов значения разрядов равно 1, то операция возвращает 1, иначе возвращается число 0. Например:

    Int a1 = 2; //010 int b1 = 5;//101 System.out.println(a1&b1); // результат 0 int a2 = 4; //100 int b2 = 5; //101 System.out.println(a2 & b2); // результат 4

    В первом случае у нас два числа 2 и 5. 2 в двоичном виде представляет число 010, а 5 - 101. Поразрядное умножение чисел (0*1, 1*0, 0*1) дает результат 000.

    Во втором случае у нас вместо двойки число 4, у которого в первом разряде 1, так же как и у числа 5, поэтому здесь результатом операции (1*1, 0*0, 0 *1) = 100 будет число 4 в десятичном формате.

    | (логическое сложение)

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

    Int a1 = 2; //010 int b1 = 5;//101 System.out.println(a1|b1); // результат 7 - 111 int a2 = 4; //100 int b2 = 5;//101 System.out.println(a2 | b2); // результат 5 - 101

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

    Также эту операцию называют XOR, нередко ее применяют для простого шифрования:

    Int number = 45; // 1001 Значение, которое надо зашифровать - в двоичной форме 101101 int key = 102; //Ключ шифрования - в двоичной системе 1100110 int encrypt = number ^ key; //Результатом будет число 1001011 или 75 System.out.println("Зашифрованное число: " +encrypt); int decrypt = encrypt ^ key; // Результатом будет исходное число 45 System.out.println("Расшифрованное число: " + decrypt);

    Здесь также производятся поразрядные операции. Если у нас значения текущего разряда у обоих чисел разные, то возвращается 1, иначе возвращается 0. Например, результатом выражения 9^5 будет число 12. А чтобы расшифровать число, мы применяем обратную операцию к результату.

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

    Поразрядная операция, которая инвертирует все разряды числа: если значение разряда равно 1, то оно становится равным нулю, и наоборот.

    Byte a = 12; // 0000 1100 System.out.println(~a); // 1111 0011 или -13

Операции сдвига

Операции сдвига также производятся над разрядами чисел. Сдвиг может происходить вправо и влево.

    a<

    a>>b - смещает число a вправо на b разрядов. Например, 16>>1 сдвигает число 16 (которое в двоичной системе 10000) на один разряд вправо, то есть в итоге получается 1000 или число 8 в десятичном представлении.

    a>>>b - в отличие от предыдущих типов сдвигов данная операция представляет беззнаковый сдвиг - сдвигает число a вправо на b разрядов. Например, выражение -8>>>2 будет равно 1073741822.

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

Конспект лекций по Java. Занятие 4

(none) (none) ::
(none)
( В.Фесюнов )

Операции (operators) в языке Java

Большинство операций Java просты и интуитивно понятны. Это такие операции, как +, -, *, /, <,> и др. Операции имеют свой порядок выполнения и приоритеты. Так в выражении

сначала выполняется умножение, а потом сложение, поскольку приоритет у операции умножения выше, чем у операции сложения. В выражении

сначала вычисляется a + b, а потом от результата вычитается c, поскольку порядок выполнения этих операций слева направо.

Но операции Java имеют и свои особенности. Не вдаваясь в детальное описание простейших операций, остановимся на особенностях.

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

  • Операция присваивания обозначается символом "=". Она вычисляет значение своего правого операнда и присваивает его левому операнду, а также выдает в качестве результата присвоенное значение. Это значение может быть использовано другими операциями. Последовательность из нескольких операций присваивания выполняется справа налево.

В простейшем случае все выглядит как обычно.

Здесь происходит именно то, что мы интуитивно подразумеваем, — вычисляется сумма a и b, результат заносится в x. Но вот два других примера.

В первом сначала 1 заносится в b, результатом операции является 1, потом этот результат заносится в a. Во втором примере вычисляется сумма a и b и результат теряется. Это бессмысленно, но синтаксически допустимо.

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

Это операции >, <, >=, <=, != и ==. Следует обратить внимание, что сравнение на равенство обозначается двумя знаками "=". Операндами этих операций могут быть арифметические данные, результат — типа boolean.

Операции инкремента, декремента

Это операции ++ и --. Так y++ (инкремент) является сокращенной записью y = y +1, аналогично и с операцией декремента (--).

Но с этими операциями есть одна тонкость. Они существуют в двух формах - префиксной (++y) и постфиксной (y++). Действие этих операций одно и то же — они увеличивают (операции декремента — уменьшают) свой операнд на 1, а вот результат у них разный. Префиксная форма в качестве результата выдает уже измененное на 1 значение операнда, а постфиксна -значение операнда до изменения.

A = 5; x = a++; y = ++a;

В этом фрагменте x получит значение 5, а y — 7.

Операция целочисленного деления

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

Остаток от деления (значение по модулю)

В Java имеется операция %, которая обозначает остаток от деления.

Расширенные операции присваивания

Кроме обычной операции "=" в Java существуют операции +=, -=, *=, /= и др. Это сокращенные записи. Так a += b полностью эквивалентна a = a + b. Аналогично и с другими такими операциями.

Логические операции

! — отрицание && — логическое "и" || — логическое "или"

Операнды этих операций должны быть типа boolean, результат — boolean. Операции && и || имеют одну особенность — их правый операнд может и не вычислиться, если результат уже известен по левому операнду. Так, если левый операнд операции && — ложь (false), то правый операнд вычисляться не будет, т.к. результат все равно — ложь.

Это свойство нужно учитывать, особенно тогда, когда правый операнд содержит вызов некоторой функции.

Побитовые логические операции

Это операции

& — побитовое "и" | — побитовое "или" ^ — побитовое "исключающее или" ~ — побитовое отрицание

Они выполняются для каждой пары битов своих операндов.

Операции сдвига

<< — сдвиг влево >> — сдвиг вправо >>> — беззнаковый сдвиг вправо

Эти операции сдвигают значение своего левого операнда на число бит, заданное правым операндом.

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

Это единственная тернарная операция, т.е. операция, имеющая три операнда. Соответственно, для нее используется не один знак операции, а два.

<условие> ? <выражение1> : < выражение2>

Если <условие> истинно, то результатом будет < выражение1>, иначе < выражение2>.

Например, "a < b ? a: b" вычисляет минимум из a и b.

Операция приведения типов

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

Например, пусть метод f(...) выдает long.

int x = (int)f(10);

Здесь (int) — это операция преобразования типа. Операция преобразования типа обозначается при помощи имени типа, взятого в скобки.

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

Литералы (константы)

Арифметические

Примеры арифметических констант

10 - 010 — это 8 - 0123 — это 83 (1*64 + 2*8 + 3) - 0x10 — это 16 - 0x123 — это 291 (1*256 + 2*16 +3) - 1e5 — это 100000 - 1.23e-3 — это 0.00123

Для указания типа константы применяются суффиксы: l (или L) — long, f (или F) — float, d (или D) — double. Например,

1L — единица, но типа long.

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

Логические литералы — это true (истина) и false (ложь)

Строковые литералы

Записываются в двойных кавычках, например

"это строка"

Символьные литералы

Записываются в апострофах, например "F", "ш".

В строковых и символьных литералах есть правила для записи спец. символов. Во-первых, есть набор предопределенных спец. символов. Это

- "\n" — конец строки (перевод строки) - "\r" — возврат каретки - "\t" — табуляция

и ряд других.

Во-вторых, можно явно записать код символа (нужно только знать его). Запись кода обычно выполняется в восьмеричной системе: "\001" — символ с кодом 1 и т.п.

Операторы (statements)

Оператор — выражение

Синтаксис

<выражение>;

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

A = 0; x = (a > b ? a: b); cnt++;

Условный оператор (if)

Синтаксис

If (<условие>) <оператор1>

Здесь <условие> — это логическое выражение, т.е. выражение, возвращающее true или false. Как видно из синтаксиса, часть else вляется необязательной. После if и после else стоит по одному оператору. Если нужно поместить туда несколько операторов, то нужно поставить блок . Блок начинается с "{" и заканчивается "}".

В Java принято блок ставить всегда, даже если после if или else стоит один оператор.

If (a > b) { x = a; } else { x = b; } if (flag) { flag = false; init(); }

В последнем примере flag — логическая переменная или поле, init() -метод, вызываемый, если флаг равен true (говорят, "если flag установлен").

Оператор return (уже рассматривали)

Оператор цикла по предусловию (while)

Синтаксис

While (<условие>) <оператор>

Как и в случае оператора if, в Java принято <оператор> заключать в фигурные скобки.

Int i = 0; while (more) { x /= 2; more = (++i < 10); }

В этом примере more должна быть логической переменной или полем, x — некоторой арифметической переменной или полем. Цикл выполняется 10 раз.

Оператор цикла по постусловию (do while)

Синтаксис

Do <оператор> while (<условие>);

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

Int i = 0; do { x \= 2; more = (++i < 10); } while (more);

Оператор цикла "со счетчиком" (for)

Синтаксис

For (<инициализация>; <условие>; <инкремент>) <оператор>

Заголовок такого цикла содержит три выражения (в простейшем случае). Из наименования оператора можно понять, что он служит для организации цикла со счетчиком. Поэтому выражение <инициализация> выполняется один раз перед первым витком цикла. После каждого витка цикла выполняется выражение <инкремент>, а потом выражение <условие>. Последнее выражение должно быть логическим и служит для задания условия продолжения цикла. Т.е. пока оно истинно, витки цикла будут продолжаться.

Для удобства составления операторов цикла со счетчиком в данной конструкции введено множество расширений.

  • <инициализация> может быть не выражением, а описанием с инициализацией типа "int i = 0".
  • <инициализация> может быть списком выражений через запятую, например, "i = 0, r = 1" .
  • <инкремент> тоже может быть списком выражений, например, "i++, r*=2"
  • Все составляющие (<инициализация>, <условие> и <инкремент>) являются необязательными. Для выражения <условие> это означает, что условие считается всегда истинным (т.е. выход из цикла должен быть организован какими-то средствами внутри самого цикла).

Т.е. допустим и такой цикл (бесконечный цикл):

For (;;) { . . . }

For (int i = 0; i < 10; i++) x /=2;

Это самая "экономичная" реализация цикла из предыдущих примеров.

Операторы break и continue

В Java нет операторов goto. Как известно, goto приводит к появлению неструктурированных программ. Операторы break и continue являются структурированными аналогами goto.

Они могут применяться в циклах, а break еще и в операторе выбора (switch). Выполнение оператора break приводит к немедленному завершению цикла. Оператор continue вызывает окончание текущего витка цикла и начало нового. Проверка условия в этом случае все же выполняется, так что continue может вызвать и окончание цикла.

For (int i = 0; ;i++) { if (oddOnly && i%2 == 0) continue; y = (x + 1)/x; if (y — x < 0.001) break; x = y; }

Здесь oddOnly — логическая переменная. Если она установлена, то все витки цикла с четными номерами пропускаются с использованием оператора continue;

Условие окончания цикла в данном примере проверяется в середине цикла и, если оно выполнено, то цикл прекращается при помощи оператора break.

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

Lbl: while (...) { . . . for (...) { . . . if (...) break lbl; } . . . }

Здесь оператор break вызовет прекращение как цикла for, так и while.

Оператор выбора (switch)

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

Синтаксис

Switch (<выражение>) { case <константа1>: <операторы1> case <константа2>: <операторы2> . . . }

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

Элементы "case <константа>:" являются метками перехода, если значение выражения совпадает с константой, то будет осуществлен переход на эту метку. Если значение выражения не совпадает ни с одной из констант, то все зависит от наличия фрагмента default. Если он есть, то переход происходит на метку default, если его нет, то весь оператор switch пропускается.

  • В операторе switch фрагменты case не образуют какие-либо блоки. Если после последнего оператора данного case-фрагмента стоит следующий case, то выполнение будет продолжено, начиная с первого оператора этого case-фрагмента.
  • В силу этого в операторе switch обычно применяется оператор break. Он ставится в конце каждого case-фрагмента.

Пример (файл SymbolTest.java)

Рассмотрим демонстрационную программу, в которой использованы операторы for и switch.

Эта программа генерирует случайным образом 100 символов латинского алфавита и классифицирует их как "гласные", "согласные" и "иногда гласные". В последнюю категорию отнесены символы "y" и "w".

Public class SymbolTest { public static void main(String args) { for (int i = 0; i < 100; i++) { char c = (char)(Math.random()*26 + "a"); System.out.print(c + ": "); switch (c) { case "a": case "e": case "i": case "o": case "u": System.out.println("гласная"); break; case "y": case "w": System.out.println("иногда гласная"); break; default: System.out.println("согласная"); } } } }

В данном примере есть несколько новых для нас элементов.

  • Используется метод random() класса Math. Посмотрим документацию по классу Math и разберемся, что он делает.
  • В операторе char c = (char)(Math.random()*26 + "a"); производится сложение арифметического значения с символом. При таком сложении в Java символ преобразуется в число, которое равно коду этого символа.
  • В операторе System.out.print(c + ": "); используется не println(...), а print(...). Метод print(...) отличается от println(...) только тем, что не переводит печать на новую строку, так что следующий оператор print(...) или println(...) продолжит печать в той же строке.

Следует также обратить внимание на фрагменты case. Формально здесь 7 таких фрагментов, но 5 из них не содержат никаких операторов. Так что, можно считать, что здесь 2 case-фрагмента, но каждый из них имеет несколько меток case.

Задание на дом

  • 1 Изменить SymbolTest.java так, чтобы количество генерируемых символов задавалось параметром вызова программы.
  • 2 Написать программу, которая в качестве параметров вызова принимает два числа - длины катетов прямоугольного треугольника, а в качестве результата печатает углы в градусах.


(none)



Есть вопросы?

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: