Какие из следующих операторов называются укороченными
Перейти к содержимому

Какие из следующих операторов называются укороченными

  • автор:

Укороченные логические операторы

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

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

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

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

Укороченная логическая операция И выполняется с помощью оператора && , а укороченная логическая операция ИЛИ — с помощью оператора || . Этим укороченным логическим операторам соответствуют обычные логические операторы & и | . Единственное отличие укороченного логического оператора от обычного заключается в том, что второй его операнд вычисляется только по мере необходимости.

В приведенном ниже примере программы демонстрируется применение укороченного логического оператора И. В этой программе с помощью операции деления по модулю определяется следующее: делится ли значение переменной d на значение переменной n нацело. Если остаток от деления n/d равен нулю, то n делится на d нацело.

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

// Продемонстрировать применение укороченных логических операторов. using System; class SCops < static void Main() < int n, d; n = 10; d = 2; if (d != 0 && (n % d) == 0) Console.WriteLine(n + " делится нацело на " + d); d = 0; // задать нулевое значение переменной d // d равно нулю, поэтому второй операнд не вычисляется if (d != 0 && (n % d) == 0) Console.WriteLine(n + " делится нацело на " + d); // Если теперь попытаться сделать то же самое без укороченного // логического оператора, то возникнет ошибка из-за деления на нуль. if (d != 0 & (n % d) == 0) Console.WriteLine(n + " делится нацело на " + d); >>

Для исключения ошибки из-за деления на нуль в операторе if сначала проверяется условие: равно ли нулю значение переменной d . Если оно равно нулю, то на этом выполнение укороченного логического оператора И завершается, а последующая операция деления по модулю не выполняется. Так, при первой проверке значение переменной d оказывается равным 2, поэтому выполняется операция деления по модулю. А при второй проверке это значение оказывается равным нулю, следовательно, операция деления по модулю пропускается, чтобы исключить деление на нуль. И наконец, выполняется обычный логический оператор И, когда вычисляются оба операнда. Если при этом происходит деление на нуль, то возникает ошибка при выполнении.

Укороченные логические операторы иногда оказываются более эффективными, чем их обычные аналоги. Так зачем же нужны обычные логические операторы И и ИЛИ? Дело в том, что в некоторых случаях требуется вычислять оба операнда логической операции И либо ИЛИ из-за возникающих побочных эффектов. Рассмотрим следующий пример программы.

// Продемонстрировать значение побочных эффектов. using System; class SideEffects < static void Main() < int i; bool someCondition = false; i = 0; // Значение переменной i инкрементируется, // несмотря на то, что оператор if не выполняется. if (someCondition & (++i < 100)) Console.WriteLine("Не выводится"); Console.WriteLine("Оператор if выполняется: " + i); // выводится 1 // В данном случае значение переменной i не инкрементируется, // поскольку инкремент в укороченном логическом операторе опускается. if (someCondition && (++i < 100)) Console.WriteLine("Не выводится"); Console.WriteLine("Оператор if выполняется: " + i); // по-прежнему 1 !! >>

Прежде всего обратим внимание на то, что переменная someCondition типа bool инициализируется значением false . Далее проанализируем каждый оператор if . Как следует из комментариев к данной программе, в первом операторе if переменная i инкрементируется, несмотря на то, что значение переменной someCondition равно false . Когда применяется логический оператор & , как это имеет место в первом операторе if , выражение в правой части этого оператора вычисляется независимо от значения выражения в его левой части. А во втором операторе if применяется укороченный логический оператор. В этом случае значение переменной i не инкрементируется, поскольку левый операнд (переменная someCondition ) имеет значение false , следовательно, выражение в правой части данного оператора пропускается. Из этого следует вывод: если в коде предполагается вычисление правого операнда логической операции И либо ИЛИ, то необходимо пользоваться неукороченными формами логических операций, доступных в C#.

И последнее замечание: укороченный оператор И называется также условным логическим оператором И, а укороченный оператор ИЛИ — условным логическим оператором ИЛИ.

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

Логические операторы языка Java выполняются только с операндами типа boolean .

Следующая таблица перечисляет логические операторы языка Java:

Операция Описание
& Логическая операция И (AND) или конъюнкция
| Логическая операция ИЛИ (OR) или дизъюнкция
^ Логическая операция исключающее ИЛИ (XOR)
! Логическая унарная операция НЕ (NOT)
|| Укороченная логическая операция ИЛИ (short-circuit)
&& Укороченная логическая операция И (short-circuit)
== Равенство
!= Неравенство
&= Логическая операция И с присваиванием
|= Логическая операция ИЛИ с присваиванием
^= Логическая операция исключающее ИЛИ с присваиванием

1. Логические операторы OR, AND, XOR, NOT.

Начнем с операций OR(|), AND(&), XOR(^), NOT(!). Операторы OR, AND, XOR являются бинарными — они требуют два оператора. NOT — это унарный оператор, только один оператор участвует в операции. Результаты выполнения этих логических операций представлены в следующей таблице:

A B A|B A&B
A^B
!A
false false false false false true
true false true false true false
false true true false true true
true true true true false false

OR (|) — результат будет true , если хотя бы одно значение равно true . Пример: для того, чтобы забрать ребенка из садика, должна прийти либо мать, либо отец, либо оба — в любом случае результат будет положительный. Если же никто не придет, ребенка не заберут — результат будет отрицательный.

AND (&) — результат будет true , только если и A, и B равны true . Пример: для того чтобы свадьба состоялась, и невеста (A) и жених (B) должны явиться на бракосочетание, иначе оно не состоится.

XOR (^) — результат будет true , только если или A равно true , или В равно true . Пример: у двух друзей на двоих один велосипед, поездка на велосипеде состоится только если один из них поедет на нем. Вдвоем они ехать не могут.

NOT (!) — инвертирование значения. Если значение было true, то станет false , и наоборот.

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

public class BooleanLogic1 < public static void main(String[] args) < boolean a = true; boolean b = false; boolean c = 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 header3">2. Укороченные логические операторы (short-circuit). 

Чаще всего в языке Java используются так называемые укороченные логические операторы (short-circuit):

|| - Укороченный логический оператор ИЛИ
&& - Укороченный логический оператор И

Правый операнд сокращенных операций вычисляется только в том случае, если от него зависит результат операции, то есть если левый операнд конъюнкции имеет значение true, или левый операнд дизъюнкции имеет значение false.

В формальной спецификации языка Java укороченные логические операции называются условными.

В следующем примере правый операнд логического выражения вычисляться не будет, так как условие d!=0 не выполняется и нет смысла дальше вычислять это выражение:

public class BooleanLogic2 < public static void main(String[] args) < int d = 0; int num = 10; if (d != 0 && num / d >10) < System.out.println("num language-java">public class BooleanLogic3 < public static void main(String[] args) < int a = 1; int b = 2; int x = 3; System.out.print(a < x && x < b); // System.out.print(a < x < b);//Ошибка компиляции >>

3. Операции ==, !=.

Здесь все просто - чтобы сравнить два значения типа boolean , можно использовать знаки == (проверка на равенство) и != (проверка на неравенство):

public class BooleanLogic4 < public static void main(String[] args) < boolean b1 = true; boolean b2 = false; System.out.println(b1 == b2); System.out.println(b1 != b2); >>

4. Операции с присваиванием.

Также существуют операции с присваиванием для AND, OR, XOR. Посмотрим пример:

public class BooleanLogic5 < public static void main(String[] args) < boolean b1 = true; boolean b2 = true; b1 &= b2;//равносильно b1 = b1 & b2; System.out.println(b1); b1 |= b2; //равносильно b1 = b1 | b2; System.out.println(b1); b1 ^= b2; //равносильно b1 = b1 ^ b2; System.out.println(b1); >>

Презентацию с видео можно скачать на Patreon .

Программирование / 3 Основные понятия С#

Console.WriteLine(); // Приведение типа int к типу byte без потери данных i = 255; b = (byte) i; Console.WriteLine("b после присваивания 255: " + b + " -- без потери данных."); // Приведение типа int к типу byte с потерей данных i = 257; b = (byte) i; Console.WriteLine("b после присваивания 257: " + b + " — с потерей данных."); Console.WriteLine(); // Приведение типа uint к типу short без потери данных u = 32000; s = (short) u; Console.WriteLine("s после присваивания 32000: " + s + " — без потери данных."); // Приведение типа uint к типу short с потерей данных u = 64000; s = (short) u; Console.WriteLine("s после присваивания 64000: " + s + " — с потерей данных."); Console.WriteLine(); // Приведение типа long к типу uint без потери данных. L = 64000; u = (uint) l; Console.WriteLine("u после присваивания 64000: " + u + " -- без потери данных."); // Приведение типа long к типу uint с потерей данных. l = -12; u = (uint) l; Console.WriteLine("u после присваивания -12: " + u + " — с потерей данных."); Console.WriteLine(); // Приведение типа int к типу char b = 88; // код ASCII символа X ch = (char) b; Console.WriteLine("ch после присваивания 88: " + ch); > > Вот какой результат дает выполнение этой программы. Целочисленный результат деления х / у: 3 b после присваивания 255: 255 -- без потери данных. b после присваивания 257: 1 -- с потерей данных. s после присваивания 32000: 32000 -- без потери данных. s после присваивания 64000: -1536 -- с потерей данных. u после-присваивания 64000: 64000 -- без потери данных. u после присваивания -12: 4294967284 -- с потерей данных. ch после присваивания 88: X Рассмотрим каждую операцию присваивания в представленном выше примере программы по отдельности. Вследствие приведения результата деления х/у к типу int отбрасывается дробная часть числа, а следовательно, теряется часть информации. Когда переменной b присваивается значение 255, то информация не теряется, поскольку это значение входит в диапазон представления чисел для типа byte . Но когда переменной b присваивается значение 257 , то часть информации теряется, поскольку это значение превышает диапазон представления чисел для типа byte . Приведение типов требуется в обоих случаях, поскольку неявное преобразование типа int в тип byte невозможно. Когда переменной s типа short присваивается значение 32000 переменной u типа uint , потери данных не происходит, поскольку это значение входит в диапазон представления чисел для типа short . Но в следующей операции присваивания переменная и имеет значение 64000, которое оказывается вне диапазона представления чисел для типа short , и поэтому данные теряются. Приведение типов требуется в обоих случаях, поскольку неявное преобразование типа uint в тип short невозможно. Далее переменной u присваивается значение 64000 переменной l типа long . В этом случае данные не теряются, поскольку значение 64000 оказывается вне диапазона представления чисел для типа uint . Но когда переменной и присваивается значение -12, данные теряются, поскольку отрицательные числа также оказываются вне диапазона представления чисел для типа uint .

Приведение типов требуется в обоих случаях, так как неявное преобразование типа long в тип uint невозможно. И наконец, когда переменной char присваивается значение типа byte , информация не теряется, но приведение типов все же требуется. Преобразование типов в выражениях Помимо операций присваивания, преобразование типов происходит и в самих выражениях. В выражении можно свободно смешивать два или более типа данных, при условии их совместимости друг с другом. Например, в одном выражении допускается применение типов short и long , поскольку оба типа являются числовыми. Когда в выражении смешиваются разные типы данных, они преобразуются в один и тот же тип по порядку следования операций. Преобразования типов выполняются по принятым в C# правилам продвижения типов. Ниже приведен алгоритм, определяемый этими правилами для операций с двумя операндами. ЕСЛИ один операнд имеет тип decimal , ТО и второй операнд продвигается к типу decimal (но если второй операнд имеет тип float или double , результат будет ошибочным). ЕСЛИ один операнд имеет тип double , ТО и второй операнд продвигается к типу double . ЕСЛИ один операнд имеет тип float , ТО и второй операнд продвигается к типу float . ЕСЛИ один операнд имеет тип ulong , ТО и второй операнд продвигается к типу ulong (но если второй операнд имеет тип sbyte , short , int или long , результат будет ошибочным). ЕСЛИ один операнд имеет тип long , ТО и второй операнд продвигается к типу long . ЕСЛИ один операнд имеет тип uint , а второй – тип sbyte , short или int , ТО оба операнда продвигаются к типу long . ЕСЛИ один операнд имеет тип uint , ТО и второй операнд продвигается к типу uint . ИНАЧЕ оба операнда продвигаются к типу int . Относительно правил продвижения типов необходимо сделать ряд важных замечаний. Вопервых, не все типы могут смешиваться в выражении. В частности, неявное преобразование типа float или double в тип decimal невозможно, как, впрочем, и смешение типа ulong с любым целочисленным типом со знаком. Для смешения этих типов требуется явное их приведение. Во-вторых, особого внимания требует последнее из приведенных выше правил. Оно гласит: если ни одно из предыдущих правил не применяется, то все операнды продвигаются к типу int . Следовательно, все значения типа char , sbyte , byte , ushort и short продвигаются к типу int в целях вычисления выражения. Такое продвижение типов называется целочисленным. Это также означает, что результат выполнения всех арифметических операций будет иметь тип не ниже int . Следует иметь в виду, что правила продвижения типов применяются только к значениям, которыми оперируют при вычислении выражения. Так, если значение переменной типа byte продвигается к типу int внутри выражения, то вне выражения эта переменная по-прежнему относится к типу byte . Продвижение типов затрагивает только вычисление выражения. Но продвижение типов может иногда привести к неожиданным результатам. Если, например, в арифметической операции используются два значения типа byte , то происходит следующее. Сначала операнды типа byte продвигаются к типу int . А затем выполняется операция, дающая результат типа int . Следовательно, результат выполнения операции, в которой участвуют два значения типа byte , будет иметь тип int . Но ведь это не тот результат, который можно было бы с очевидностью предположить. Рассмотрим следующий пример программы. // Пример неожиданного результата продвижения типов! using System; class PromDemo < static void Main() < byte b; b = 10; b = (byte) (b * b); // Необходимо приведение типов!! Console.WriteLine("b: "+ b); >>

Как ни странно, но когда результат вычисления выражения b*b присваивается обратно переменной b , то возникает потребность в приведении к типу byte ! Объясняется это тем, что в выражении b*b значение переменной b продвигается к типу int и поэтому не может быть присвоено переменной типа byte без приведения типов. Имейте это обстоятельство в виду, если получите неожиданное сообщение об ошибке несовместимости типов в выражениях, которые, на первый взгляд, кажутся совершенно правильными. Аналогичная ситуация возникает при выполнении операций с символьными операндами. Например, в следующем фрагменте кода требуется обратное приведение к типу char , поскольку операнды ch1 и ch2 в выражении продвигаются к типу int . char ch1 = 'a', ch2 = 'b'; ch1 = (char) (ch1 + ch2); Без приведения типов результат сложения операндов ch1 и ch2 будет иметь тип int , и поэтому его нельзя присвоить переменной типа char . Продвижение типов происходит и при выполнении унарных операций, например с унарным минусом. Операнды унарных операций более мелкого типа, чем int ( byte , sbyte , short и ushort ), т.е. с более узким диапазоном представления чисел, продвигаются к типу int . То же самое происходит и с операндом типа char . Кроме того, если выполняется унарная операция отрицания значения типа uint , то результат продвигается к типу long . Приведение типов в выражениях Приведение типов можно применять и к отдельным частям крупного выражения. Это позволяет точнее управлять преобразованиями типов при вычислении выражения. Рассмотрим следующий пример программы, в которой выводятся результат отношения двух переменных y и x и отдельно целая и дробная части числового результата отношения. Для этого в данной программе применяется приведение типов, благодаря которому результат, отношения преобразуется в тип int . // Пример приведения типов в выражениях. using System; class CastExpr < static void Main() < double x, y; x = 1.5; y = 4.3; Console.WriteLine("Отношние y/x = " + y/x); Console.WriteLine("Целая часть отношения y/x p177 ft18">Console.WriteLine("Дробная часть отношения y/x p80 ft16">> > Вот как выглядит результат выполнения этой программы. Отношние y/x = 2,86666666666667 Целая часть отношения y/x = 2 Дробная часть отношения y/x = 0,86666666666667 Как видите, приведение результата, возвращаемого отношением y/x , к типу int позволяет получить целую часть числа. Так, в выражении ((y/x) - (int) (y/x))

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

3.3.4. Операторы В языке C# предусмотрен обширный ряд операторов, предоставляющих программисту возможность полного контроля над построением и вычислением выражений. Большинство операторов в C# относится к следующим категориям: арифметические, поразрядные, логические и операторы отношения . Все перечисленные категории операторов рассматриваются в этом разделе. Кроме того, в C# предусмотрен ряд других операторов для особых случаев, включая индексирование массивов, доступ к членам класса и обработку лямбда-выражений. Эти специальные операторы рассматриваются позже. 3.3.4.1. Арифметические операторы Арифметические операторы, представленные в языке C#, приведены ниже. Таблица 4. Арифметические операторы

Оператор Действие
+ Сложение
- Вычитание, унарный минус
* Умножение
/ Деление
% Деление по модулю
-- Декремент
++ Инкремент

Операторы + , - , * и / действуют так, как предполагает их обозначение. Их можно применять к любому встроенному числовому типу данных. Действие арифметических операторов не требует особых пояснений, за исключением следующих особых случаев. Прежде всего, не следует забывать, что когда оператор / применяется к целым числам, то любой остаток от деления отбрасывается. Например, результат целочисленного деления 10/3 будет равен 3 . Остаток от этого деления можно получить с помощью оператора деления по модулю % , который иначе называется оператором вычисления остатка. Он возвращяет остаток от целочисленного деления. Например, 10%3 равно 1 . В C# оператор % можно применять как к целочисленным типам данных, так и к типам с плавающей точкой. Поэтому 10.0%3.0 также равно 1 . В этом отношении C# отличается от языков C и C++, где операции деления по модулю разрешаются только для целочисленных типов данных. 3.3.4.2. Операторы инкремента и декремента Операторы инкремента « ++ » увеличивает свой операнд на 1, а оператор декремента « -- » уменьшает операнд на 1. Следовательно, оператор x++; равнозначен оператору х = x + 1; а оператор х--; равносилен оператору х = x - 1; Следует, однако, иметь в виду, что в инкрементной или декрементной форме значение переменной х вычисляется только один, а не два раза. В некоторых случаях это позволяет повысить эффективность выполнения программы. Оба оператора инкремента и декремента можно указывать до операнда (в префиксной форме) или же после операнда (в постфиксной форме). Например, оператор

х = x + 1; может быть записан в следующем виде: ++х; // префиксная форма или же в таком виде: х++; // постфиксная форма Когда оператор инкремента или декремента предшествует своему операнду, то результатом операции становится значение операнда после инкремента или декремента. А когда оператор инкремента или декремента следует после своего операнда, то результатом операции становится значение операнда до инкремента или декремента . Рассмотрим следующий фрагмент кода. х = 10; у = ++х; В данном случае значение переменной y будет установлено равным 11, поскольку значение переменной х сначала увеличивается на 1, а затем присваивается переменной y . Но во фрагменте кода x = 10; у = х++; значение переменной y будет установлено равным 10, так как в этом случае значение переменной х сначала присваивается переменной у , а затем увеличивается на 1. В обоих случаях значение переменной x оказывается равным 11. Отличие состоит лишь том, когда именно это значение станет равным 11: до или после его присваивания переменной y . Возможность управлять моментом инкремента или декремента дает немало преимуществ при программировании. И еще одно замечание: не пугайтесь выражений, подобных следующему: у + ++x Такое расположение рядом двух операторов может показаться не совсем привычным, но компилятор воспримет их в правильной последовательности. Нужно лишь запомнить, что в данном выражении значение переменной y складывается с увеличенным на 1 значением переменной x . 3.3.4.3. Операторы отношения и логические операторы В обозначениях оператор отношения и логический оператор термин отношения означает взаимосвязь, которая может существовать между двумя значениями, а термин логический – взаимосвязь между логическими значениями « истина » и « ложь ». И поскольку операторы отношения дают истинные или ложные результаты, то они нередко применяются вместе с логическими операторами. Именно по этой причине они и рассматриваются совместно в данном разделе.

Ниже перечислены операторы отношения и логические операторы.
Таблица 5. Операторы отношения Таблица 6. Логические операторы
Оператор Значение
== Равно
!= Не равно
> Больше
Меньше
>= Больше или равно
Меньше или равно
Оператор Значение
& И
| ИЛИ
^ Исключающее ИЛИ
&& Укороченное И
|| Укороченное ИЛИ
! НЕ

Результатом выполнения оператора отношения или логического оператора является логическое значение типа bool . В целом, объекты можно сравнивать на равенство или неравенство, используя операторы отношения == и != . А операторы сравнения < , >, <= или >= могут применяться только к тем типам данных, которые поддерживают отношение порядка. Следовательно, операторы отношения можно применять ко всем числовым типам данных. Но значения типа bool могут сравниваться только на равенство или неравенство, поскольку истинные ( true ) и ложные ( false ) значения не упорядочиваются. Например, сравнение true > false в C# не имеет смысла. Операнды логических операторов должны относиться к типу bool , а результат выполнения логической операции также относится к типу bool . Логические операторы & , | , ^ и ! поддерживают основные логические операции И, ИЛИ, исключающее ИЛИ и НЕ в соответствии с приведенной ниже таблицей истинности. Таблица 7. Таблица истинности операций И, ИЛИ, исключающее ИЛИ, НЕ

p q p & q p | q p ^ q !p
false false false false false true
true false false true true false
false true false true true true
true true true true false false

Как следует из приведенных выше таблиц, результатом выполнения логической операции исключающее ИЛИ будет истинное значение ( true ), если один и только один ее операнд имеет значение true . Ниже приведен пример программы, демонстрирующий применение нескольких операторов отношения и логических операторов. //Продемонстрировать применение операторов // отношения и логических операторов. using System; < class RelLogOps < static void Main() < int i, j; bool b1, b2; i = 10; j = 11; Console .WriteLine( "i < j \t- " + (i < j)); Console .WriteLine( "i <= j \t- " + (i <= j)); Console .WriteLine( "i != j \t- " + (i != j)); Console .WriteLine( "i == j \t- " + (i == j)); Console .WriteLine( "i >= j \t- " + (i >= j)); Console .WriteLine( "i > j \t- " + (i > j)); b1 = true ; b2 = false ; Console .WriteLine( "b1 & b2 \t- " + (b1 & b2)); Console .WriteLine( "!(b1 & b2) \t- " + !(b1 & b2)); Console .WriteLine( "b1 | b2 \t- " + (b1 | b2)); Console .WriteLine( "b1 ^ b2 \t- " + (b1 ^ b2)); Console .ReadKey(); > > > Выполнение этой программы дает следующий результат:

i < j - True
i j - True
i != j - True
i == j - False
i >= j - False
i > j - False
b1 & b2 - False
!(b1 & b2) - True
b1 | b2 - True
b1 ^ b2 - True

Логические операторы в C# выполняют наиболее распространенные логические операции. Тем не менее существует ряд операций, выполняемых по правилам формальной логики. Эти логические операции могут быть построены с помощью логических операторов, поддерживаемых в С#. Следовательно, в С# предусмотрен такой набор логических операторов, которого достаточно для построения практически любой логической операции, в том числе импликации. Импликация – это двоичная операция, результатом которой является ложное значение только в том случае, если левый ее операнд имеет истинное значение, а правый — ложное. (Операция импликации отражает следующий принцип: истина не может подразумевать ложь). Ниже приведена таблица истинности для операции импликации. Таблица 8. Таблица истинности операции импликации

p q Результат импликации p и q
true true true
true false false
false false true
false true true

Операция импликации может быть осуществлена с помощью логических операторов ! и | : !р | q 3.3.4.4. Укороченные логические операторы В C# предусмотрены также специальные, укороченные, варианты логических операторов И и ИЛИ, предназначенные для получения более эффективного кода. Поясним это на следующих примерах логических операций. Если первый операнд логической операции И имеет ложное значение ( false ), то ее результат будет иметь ложное значение независимо от значения второго операнда. Если же первый операнд логической операции ИЛИ имеет истинное значение ( true ), то ее результат будет иметь истинное значение независимо от значения второго операнда. Благодаря тому что значение второго операнда в этих операциях вычислять не нужно, экономится время и повышается эффективность кода. Укороченная логическая операция И выполняется с помощью оператора && , а укороченная логическая операция ИЛИ — с помощью оператора || . Этим укороченным логическим операторам соответствуют обычные логические операторы & и | . Отличие укороченного логического оператора от обычного заключается в том, что второй его операнд вычисляется только по мере необходимости. Кроме того, укороченные операторы принимают в качестве операндов только величины типа bool. Укороченные логические операторы иногда оказываются более эффективными, чем их обычные аналоги. Так зачем же нужны обычные логические операторы И и ИЛИ? Дело в том, что в некоторых случаях требуется вычислять оба операнда логической операции И либо ИЛИ из-за возникающих побочных эффектов. 3.3.4.5. Оператор присваивания Оператор присваивания обозначается одиночным знаком равенства « = ». В C# оператор присваивания действует таким же образом, как и в других языках программирования. Ниже приведена его общая форма: имя_переменной = выражение

здесь имя_переменной должно быть совместимо с типом выражения.

У оператора присваивания имеется одна интересная особенность, о которой вам будет полезно знать: он позволяет создавать цепочку операций присваивания. Рассмотрим, например, следующий фрагмент кода: int х, у, z; х = у = z = 100; // присвоить значение 100 переменным х, у и z В приведенном выше фрагменте кода одно и то же значение 100 задается для переменных х , у и z с помощью единственного оператора присваивания. Это значение присваивается сначала переменной z , затем переменной у и, наконец, переменной х . Такой способ присваивания "по цепочке" удобен для задания общего значения целой группе переменных. 3.3.4.6. Составные операторы присваивания В C# предусмотрены специальные составные операторы присваивания, упрощающие программирование некоторых операций присваивания. Для многих операций, требующих наличия двух операндов, существуют отдельные составные операторы присваивания. Общая форма всех этих операторов имеет следующий вид: имя_переменной ор = выражение где ор — арифметический или логический оператор, применяемый вместе с оператором присваивания. Ниже перечислены составные операторы присваивания для арифметических и логических операций:

Арифметические += -= *= /= %=
Логические &= |= ^=
Сдвиг >>=

Для пояснения принципа их работы обратимся к простому примеру. Приведенный ниже оператор присваивания x = x + 10; можно переписать, используя следующий составной оператор присваивания. x += 10; Пара операторов += указывает компилятору на то, что переменной х должно быть присвоено ее первоначальное значение, увеличенное на 10. Рассмотрим еще один пример. Оператор х = х - 100; и оператор x -= 100; выполняют одни и те же действия. Оба оператора присваивают переменной х ее первоначальное значение, уменьшенное на 100. Аналогично действуют остальные составные операторы присваивания: Таблица 9. Составные операторы присваивания

Оператор Значение
x += a переменной х присваивается ее первоначальное значение, увеличенное на a
x -= a переменной х присваивается ее первоначальное значение, уменьшенное на a
x *= a переменной х присваивается ее первоначальное значение, увеличенное в a раз
x /= a переменной х присваивается ее первоначальное значение, уменьшенное в a раз
x %= a переменной х присваивается остаток от деления ее первоначальнго значения и a
x &= a переменной х присваивается результат логической операции И над ее
первоначальным значением и a
x |= a переменной х присваивается результат логической операции ИЛИ над ее
первоначальным значением и a
x ^= a переменной х присваивается результат логической операции исключающее ИЛИ над
ее первоначальным значением и a
x >>= a переменной х присваивается результат сдвига ее первоначального значения на a бит
вправо
x

переменной х присваивается результат сдвига ее первоначального значения на a бит
влево

Составные операторы присваивания записываются более кратко, чем их несоставные эквиваленты. Поэтому их иногда еще называют укороченными операторами присваивания. У составных операторов присваивания имеются два главных преимущества. Во-первых, они более компактны, чем их "несокращенные" эквиваленты. И во-вторых, они дают более эффективный исполняемый код, поскольку левый операнд этих операторов вычисляется только один раз. Именно по этим причинам составные операторы присваивания чаще всего применяются в программах, профессионально написанных на С#. 3.3.4.7. Поразрядные операторы В C# предусмотрен ряд поразрядных операторов, расширяющих круг задач, для решения которых можно применять С#. Поразрядные операторы воздействуют на отдельные двоичные разряды (биты) своих операндов. Они определены только для целочисленных операндов, поэтому их нельзя применять к данным типа bool , float или double . Эти операторы называются поразрядными, поскольку они служат для проверки, установки или сдвига двоичных разрядов, составляющих целое значение. Среди прочего поразрядные операторы применяются для решения самых разных задач программирования на уровне системы, включая, например, анализ информации состояния устройства. Все доступные в C# поразрядные операторы приведены в таблице:

Таблица 10. Поразрядные операторы
Оператор Значение
& Поразрядное И
| Поразрядное ИДИ
^ Поразрядное исключающее ИДИ
>> Сдвиг вправо
Сдвйг влево
~ Дополнение до 1 (унарный оператор НЕ)

Поразрядные операторы И, ИЛИ, исключающее ИЛИ и НЕ Поразрядные операторы И, ИЛИ, исключающее ИЛИ и НЕ обозначаются следующим образом: & , | , ^ и ~ . Они выполняют те же функции, что и их логические аналоги, рассмотренные ранее. Но в отличие от логических операторов, порязрядные операторы действуют на уровне отдельных двоичных разрядов, то есть выполняют логическую операцию между соответствующими разрядами чисел – их операндов. Ниже приведены результаты порязрядных операций с двоичными единицами и нулями.

p q p & q p | q p ^ q ~p
0 0 0 0 0 1
1 0 0 1 1 0
0 1 0 1 1 1
1 1 1 1 0 0

С точки зрения наиболее распространенного применения, поразрядную операцию И можно рассматривать как способ подавления отдельных двоичных разрядов. Это означает, что если какой-нибудь бит в любом из операндов равен 0, то соответствующий бит результата будет сброшен в 0. Например: 1101 0011 1010 1010 & _________ 1000 0010 Поразрядный оператор ИЛИ может быть использован для установки отдельных двоичных разрядов. Если в 1 установлен какой-нибудь бит в любом из операндов этого оператора, то в 1 будет установлен и соответствующий бит в другом операнде. Например, если нужно установить некоторый разряд в значение 1: 1101 0011 0010 0000 | _________ 1111 0011 Поразрядный оператор исключающее ИЛИ устанавливает двоичный разряд операнда в том и только в том случае, если двоичные разряды сравниваемых операндов оказываются разными, как в приведенном ниже примере. 0111 1111 1011 1001 ^ _________ 1100 0110 У поразрядного оператора исключающее ИЛИ имеется одно интересное свойство, которое оказывается полезным в самых разных ситуациях. Так, если выполнить сначала поразрядную операцию исключающее ИЛИ одного значения X с другим значением Y , а затем такую же операцию над результатом предыдущей операции и значением Y , то вновь получится первоначальное значение X . Это означает, что в приведенном ниже фрагменте кода R1 = X ^ Y; R2 = R1 ^ Y; значение переменной R2 оказывается в итоге таким же, как и значение переменной X . Следовательно, в результате двух последовательно выполняемых поразрядных операций исключающее ИЛИ, в которых используется одно и то же значение, получается первоначальное значение. Этим свойством данной операции можно воспользоваться для написания простой программы шифрования, в которой некоторое целое значение служит в качестве ключа для кодирования и декодирования сообщения с помощью операции исключающее ИЛИ над символами этого сообщения. В первый раз операция исключающее ИЛИ выполняется для кодирования открытого текста в зашифрованный, а второй раз – для декодирования зашифрованного текста в открытый. Разумеется, такое шифрование не представляет никакой практической ценности, поскольку оно может быть легко разгадано. Тем не менее оно служит интересным примером для демонстрации результатов применения поразрядных операторов исключающее ИЛИ. Поразрядный унарный оператор НЕ (или оператор дополнения до 1) изменяет на обратное состояние все двоичные разряды операнда. Так, если некоторое целое значение А представлено комбинацией двоичных разрядов 1001 0110, то в результате поразрядной операции ~А получается значение, представленное следующей комбинацией двоичных разрядов 0110 1001.

Какие из следующих операторов называются укороченными

Как следует из приведенной выше таблицы, результатом выполнения логической операции исключающее ИЛИ будет истинное значение (true), если один и только один ее операнд имеет логическое значение true.

Приведенный ниже пример программы демонстрирует применение некоторых операторов отношения и логических операторов. // Демонстрация операторов отношения и логических операторов, class RelLogOps < public static void main(String args[]) < int i, j; boolean bl, b2; i = 10; j = 11; if(i < j) System.out.println("i < j"); if(i = j) System.out.println("this won't execute"); if(i > j) System.out.println("this won't execute"); bl = true; b2 = false; if(bl & b2) System.out.println("this won't execute"); if(! (bl & b2)) System.out.println("! (bl & b2) is true"); if(bl | b2) System.out.println("bl | b2 is true"); if(bl A b2) System.out.println("bl A b2 is true"); > >

В Java предусмотрены также специальные, укороченные варианты логических операторов И и ИЛИ, предназначенные для получения более эффективного кода. Поясним это на следующих примерах логических операций. Если первый операнд логической операции И имеет ложное значение (false), то ее результат будет иметь ложное значение независимо от значения второго операнда. Если же первый операнд логической операции ИЛИ имеет истинное значение (true), то ее результат будет иметь истинное значение независимо от значения второго операнда. Благодаря тому что значение второго операнда в этих операциях вычислять не нужно, экономится время и повышается эффективность кода.

Укороченная логическая операция И выполняется с помощью оператора 66, а укороченная логическая операция ИЛИ — с помощью оператора | |. Этим укороченным логическим операторам соответствуют обычные логические операторы & и |. Единственное отличие укороченного логического оператора от обычного заключается в том, что второй его операнд вычисляется только по мере необходимости.

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

И последнее замечание: в формальной спецификации Java укороченный оператор И называется условным логическим оператором И, а укороченный оператор ИЛИ — условным логическим оператором ИЛИ, но чаще подобные операторы называются укороченными. Оператор присваивания

Оператор присваивания уже не раз применялся в примерах программ, начиная с главы 1. И теперь настало время дать ему формальное определение. Оператор присваивания обозначается одиночным знаком равенства (=). В Java он выполняет те же действия, что и в других языках программирования. Ниже приведена общая форма этого оператора. переменная = выражение

где переменная и выражение должны иметь совместимые типы.

У оператора присваивания имеется одна интересная особенность, о которой вам будет полезно знать: он позволяет создавать цепочку операций присваивания. Рассмотрим, например, следующий фрагмент кода: int х, у, z; x=y=z=100; // присвоить значение 100 переменным х, у и z

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

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

можно переписать, используя следующий укороченный оператор присваивания: х += 10;

Пара операторов += указывает компилятору на то, что переменной х должно быть присвоено ее первоначальное значение, увеличенное на 10.

Рассмотрим еще один пример. Оператор х = х - 100;

и оператор х -= 100;

выполняют одни и те же действия. Оба оператора присваивают переменной х ее первоначальное значение, уменьшенное на 100.

Для многих двоичных операций в Java, т.е. операций, требующих наличия двух операндов, существуют отдельные укороченные операторы присваивания. Общая форма всех этих операторов имеет следующий вид: переменная ор = выражение

где ор — арифметический или логический оператор, применяемый вместе с оператором присваивания.

Ниже перечислены укороченные операторы присваивания для арифметических и логических операций. += -= *= /= %= &= |= ^=

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

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

При написании программ очень часто возникает потребность в присваивании значения, хранящегося в переменной одного типа, переменной другого типа. Например, значение int, возможно, потребуется присвоить переменной float, как показано ниже. int i; float f; i = 10; f = i; // присвоить значение переменной типа int переменной типа float

Если типы данных являются совместимыми, значение из правой части оператора присваивания автоматически преобразуется к типу данных в левой его части. Так, в приведенном выше фрагменте кода значение переменной i преобразуется в тип float, а затем присваивается переменной f. Но ведь Java — язык со строгим контролем типов, и далеко не все типы данных в нем совместимы, поэтому неявное преобразование типов выполняется не всегда. В частности, типы boolean и int не являются совместимыми.

  • Предыдущая страница
  • Следующая страница

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *