© 2008 Наталия Македа
Все материалы блога защищены авторским правом. Любая перепечатка или использование материалов этого блога в коммерческих целях возможна лишь с письменного согласия автора. При некоммерческом использовании ссылка на блог обязательна.

Показаны сообщения с ярлыком присваивание. Показать все сообщения
Показаны сообщения с ярлыком присваивание. Показать все сообщения

среда, 24 сентября 2008 г.

2.9 Оператор присваивания (Выпуск 11)

Операторы присваивания устанавливают значение переменной или выражения в новое значение. Присваивание поддерживается рядом других операторов. Простое присваивание использует знак "=". Такие операторы, как, например, "*=", "+=" выполняют композиционную функцию, имеющую значение "вычислить и присвоить". Такие композиционные операторы имеют общую форму op=, где op - любой бинарный небулевый оператор, рассмотренный в данной главе.

Для любых выражений x и y совместимого типа выражение x op= y является эквиваленным выражению x = x op y. Но есть и отличия:

  1. В первом случае x вычисляется только раз, а не два раза, как во втором, традиционном, случае.
  2. Оператор присваивания содержит в себе неявное приведение типов.

Например:

1. byte x = 2;
2. x += 3;

В расширенном варианте это выглядит так:

1. byte x = 2;
2. x = (byte)(x + 3);

Использование приведения типа к byte необходимо, потому что результат целочисленного сложения имеет по меньшей мере тип int. В первом же случае, приведение типов неявное.

Выражение x+=2 всего лишь на два символа короче своей расширенной формы x = x + 2. Но представьте себе, что x имеет более сложный вид, например:
target[temp.calculateOffset(1.9F) + depth++].item. И тогда читаемость этого выражения существенно возрастает!

Любое присваивание обладает значением

Все операторы, которые мы обсудили в данной главе возвращают некое значение в результате выполнения операции. Например, выражение 1+2 возвращает значение 3 в результате выполнения операции сложения. И это значение может быть использовано на следующих шагах программы, например, оно может быть присвоено некоторой переменной. Оператор присваивания также возвращает значение. Например, если нам даны три переменные a, b, c, то допустимо выражение a = b = c = 0. Это выражение вычисляется справа налево, то есть ноль сначала присваивается переменной c. И присваивание возвращает значение 0, которое присваивается переменной b. А потом аналогичным образом ноль присваивается переменной a.

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


Читать далее!

воскресенье, 27 апреля 2008 г.

2. Операторы и присваивания (Выпуск 4)

2. Операторы и присвоения" (Operators and assignments)

Операторы в Java используются для разнообразных операций (всех необходимых). Все Javaоператоры перечислены в Таблице 2.1:


Таблица 2.1: Операторы Java в нисходящем порядке приоритетности массива

КатегорияОператоры
Унарные++ -- + - ! ~ ()
Арифметические* / %
+ -
Сдвиг<< >> >>>
Сравнение< <= > >= instanceof
== !=
Поразрядные& ^
Быстрого принятия решения&&
Условные?:
Присвоение= op=

2.1. Порядок вычисления

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

1. int [] a = { 4, 4 };
2. int b = 1;
3. a[b] = b = 0;

Какой элемент массива модифицирован? Какое значение b использовано для выбора элемента массива: 0 или 1? Согласно правилу вычисления слева направо самое левое выражение a[b] должно быть вычислено первым. Так что это a[1]. Затем вычисляется b, то есть активируется ссылка на переменную b. Затем вычисляется константа 0, что не требует никаких операций. Затем в вычисление включаются операторы. Вычисление при этом проводится в порядке приоритетности и ассоциацивности. Для присвоений ассоциативность - справа налево. Таким образом, сначала значение 0 присваивается переменной b, которая, в свою очередь, затем присваивается последнему элементу массива a.

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

2.2. Унарные операторы

Большинство оперторов имеют два операнда. Например, когда мы производим умножение, то делаем это с двумя числами. Однако, унарные операторы применяются только к одному операнду. В Java представлены семь унарных операторов:

  • Инкремент (увеличение значения на 1) и декремент (уменьшение значения на 1): ++ и --
  • Унарный плюс и минус: + и -
  • Поразрядное инвертирование: ~
  • Логическое дополнение: !
  • Приведение типа: ( )

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

Инкремент (увеличение значения на 1) и декремент (уменьшение значения на 1): ++ и --

Эти операторы изменяют значение выражения добавлением или вычитанием 1. Например, если переменная x типа int равна 10, то ++x (--x) равно 11 (соответственно, 9). Результат записывается в x.

В предыдущих примерах операторы находились перед переменной. Они могут находиться и после неё. И ++x, и x++ дают один и тот же результат, сохраняемый в x. Но значение всего выражения отличается. Например, если y = x++, то значение y равно исходному значению x. Если же y = ++x, то значение y на единицу больше, чем исходное значение x. В обоих случаях значение x увеличивается на 1.

Если инкремент (декремент) расположен слева от выражения, то выражение модифицируется перед тем (после того), как оно начинает участвовать в остальном вычислении. Это называется пре-инкремент (пре-декремент). Соответсвенно, если оператор находится справа от выражения, то в остальном вычислении участвует исходное значение этого выражения. И инкремент (декремент) происходит после того, как вычисление всего выражения завершено.

Таблица 2.2. показывает значения x и y после применения инкремента и декремента справа и слева.


Таблица 2.2: Примеры премодификации и постмодификации инкрементом и декрементом

КатегорияОператоры
Начальное значение xВыражениеИтоговое значение yИтоговое значение x
5y = x++56
5y = ++x66
5y = x--54
5y = --x44

Унарный плюс и минус: + и -

Унарные операторы + и - отличаются от обычных бинарных операторов + и -, которые трактуются, как сложение и вычитание. Унарный + не имеет никакого эфекта, кроме подчёркивания положительной природы численного литерала. Унарный - отрицает выражение (было положительным - стало отрицательным, было отрицательным - стало положительным). Примеры:

1. x = -3;
2. y = +3;
3. z = -(y + 6);

В примере единственное обоснование использования унарного плюса - подчёркивание, что переменной y присваивается положительное число. Общее выравнивание кода также более красиво с эстетической точки зрения :). Заметим, что в третьей строке унарный оператор применяется не к литералу, а к выражению. Таким образом, значение переменной z присваивается -9.

Поразрядное инвертирование: ~

Каждый примитивный тип Java представляется в виртуальной машине так, что представление не зависит от платформы. Это означает, что битовый шаблон, используемый для представления некоего отдельного числа, будет всегда тем же самым. Таким образом и манипулирование битами - процесс более эффективный, в силу независимости от платформы. Поразрядное инвертирование означает, что в двоичном представлении числа 0 заменяется на 1, а 1 - на 0.

Например, применение этого оператора к байту с содержимым 00001111 даст 11110000.

Логическое дополнение: !

Оператор ! инвертирует логическое значение выражения. Например, !true = false. Этот оператор часто используется в тестовой части if () конструкции. Эффект этого - изменение значения логического выражения. То есть обработчики if () и else могут быть легко обменяться местами. Рассмотрим два эквивалентных фрагмента кода:

1. public Object myMethod(Object x) {
2. if (x instanceof String) {
3. // do nothing
4. }
5. else {
6. x = x.toString();
7. }
8. return x;
9. }

и

1. public Object myMethod(Object x) {
2. if (!(x instanceof String)) {
3. x = x.toString();
4. }
5. return x;
6. }

В первом фрагменте, тестирование происходит в строке 2, но присвоение - в строке 6, если тест не пройдёт. Это сделано немного громоздко при помощи ветви else конструкции if/else. Второй фрагмент использует оператор логического дополнения, поэтому во второй строке тест инвертирован и может быть прочтён как Если x не строка. Если тест проходит, то обработка происходит в третьей строке и никакого отдельного else не требуется и результирующий код более краток и более читаем.

Приведение типа: ( )

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

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

int circum = (int)(Math.PI * diameter);

Здесь приведение типа выражается фрагментом (int). Если бы этот фрагмент отсутсвовал, то компилятор бы выдал ошибку, поскольку double значение, возвращаемое арифметическим выражением не может быть точно представлено int значением, к которому присваивается. Присвоение типа - это способ, которым программист говорит компилятору: "Я знаю, что такое присвоение может быть рискованным, но верь мне, ведь я - специалист". Конечно, если результат при этом теряет точность так, что программа не функционирует должным образом, - это ответсвенность программиста.

Присвоение типа может быть применено и к объектным (непримитивным) типам. Это типично, например, для случаев, когда используются контейнеры типа Vector. Если вы помещаете объект типа String в Vector, то когда вы его извлекаете, тип, возвращаемый методом elementAt(), будет Object. Для использования извлечённого объекта как String нужно применить приведение типа, как, например, в следующем фрагменте кода:

1. Vector v = new Vector();
2. v.add ("Hello");
3. String s = (String)v.get(0);

В данном примере приведение типа имеет место в третьей строке (конструкция (String)). И хотя компилятор допускает такое приведение типа, во время выполнения программы всё равно проверяется, является объект извлечённый из Vector на самом деле объектом типа String. В будущих выпусках я расскажу о допустимых приведениях типов.


Читать далее!