13

13


Этот феномен совмещения имен часто называют синонимией (aliasing), и именно она является основным способом работы с объектами в Java. Но что делать, если совмещение имен нежелательно? Тогда можно пропустить при¬своение и записать
tl.level = t2 level;
При этом программа сохранит два разных объекта, а не «выбросит» один из них, «привязав» ссылки tl и t2 к единственному объекту. Вскоре вы поймете, что прямая работа с полями данных внутри объектов противоречит принципам объектно-ориентированной разработки. Впрочем, это непростой вопрос, так что пока вам достаточно запомнить, что присвоение объектов может таить в себе немало сюрпризов.
Совмещение имен во время вызова методов
Совмещение имен также может происходить при передаче объекта методу:
// operators/PassObject java
// Передача объектов методам может работать
// не так. как вы привыкли.
import static net.mindview.util.Print.*;
class Letter { char c;
}
public class PassObject {
static void f(Letter y) { y.c = 'z';
}
public static void main(String[] args) { Letter x = new LetterO; x.c = 'a';
printCl; x.c; " + x.c); f(x);
print("2: x.c: " + x.c);
}
} /* Output 1: x.c: a 2: x.c: z */ ///
Во многих языках программирования метод f() создал бы копию своего па¬раметра Letter у внутри своей области действия. Но из-за передачи ссылки строка
у.с = 'z';
на самом деле изменяет объект за пределами метода f().
Совмещение имен и решение этой проблемы — сложные темы. Будьте очень внимательными в таких случаях во избежание ловушек.
Арифметические операторы
Основные математические операторы остаются неизменными почти во всех языках программирования: сложение (+), вычитание (-), деление (/), умноже¬ние (*) и остаток от деления нацело (%). Деление нацело обрезает, а не округ¬ляет результат.
В Java также используется укороченная форма записи для того, чтобы одно¬временно произвести операцию и присвоение. Она обозначается оператором с последующим знаком равенства и работает одинаково для всех операторов языка (когда в этом есть смысл). Например, чтобы прибавить 4 к переменной х и присвоить результат х, используйте команду х += 4.
Следующий пример демонстрирует использование арифметических опе¬раций:
//: operators/MathOps.java // Демонстрация математических операций, import java.util.*;
import static net.mindview.util.Print.*;
public class MathOps {
public static void main(String[] args) {
// Создание и раскрутка генератора случайных чисел
Random rand = new Random(47); int i, j, k;
// Выбор значения от 1 до 100: j = rand.nextlnt(lOO) + 1: printC'j : " + j): к = rand.nextlnt(lOO) + 1. printC'k : " + k): i = J + k;
printC'j + к : " + i); 1 - J - k:
printC'j - к :" + i); i = к / j,
printC'k / j : " + i): i = к * j;
printC'k * j • " + i): i = к % j;
printC'k % j . " + i). j X= k:
printC'j %/ к • " + j); // Тесты для вещественных чисел float u.v.w; // также можно использовать double v = rand.nextFloatO; printC'v . " + v); w = rand.nextFloatO; print("w : " + w), u = v + w;
printC'v + w : " + u); u = v - w;
printC'v - w : " + u). u = v * w;
printC'v * w : " + u); u = v / w;
printC'v / w : " + u): // следующее также относится к типам // char, byte, short, int, long и double: u += v:
printC'u += v . " + u): u -= v;
printC'u -= v : " + u); u *= v:
printC'u *= v : " + u): u /= v;
printC'u /= v : " + u).
}
} /* Output: j • 59 k 56 j + k • 115 j - k • 3 k / j : 0 k * j : 3304 k % j : 56 j %= k : 3 v • 0.5309454 w : 0.0534122 v + w • 0 5843576 v - w : 0.47753322 v * w : 0.028358962
v / w 9 940527 u += v : 10.471473 u -= v 9 940527 u *= v 5 2778773 u /= v : 9 940527 */// ~
Для получения случайных чисел создается объект Random. Если он создается без параметров, Java использует текущее время для раскрутки генератора, что¬бы при каждом запуске программы выдавались разные числа.
Программа генерирует различные типы случайных чисел, вызывая соответ¬ствующие методы объекта Random: nextlnt() и nextFloat() (также можно исполь¬зовать nextLong() и nextDouble()). Аргумент nextlnt() задает верхнюю границу ге¬нерируемых чисел. Нижняя граница равна 0, но для предотвращения возмож¬ного деления на 0 результат смещается на 1.
Унарные операторы плюс и минус
Унарные минус (-) и плюс (+) внешне не отличаются от аналогичнхы бинар¬ных операторов. Компилятор выбирает нужный оператор в соответствии с кон¬текстом использования. Например, команда
х = -а;
имеет очевидный смысл. Компилятор без труда разберется, что значит
х = а * -Ь;
но читающий код может запутаться, так что яснее будет написать так:
х = а * (-Ь):
Унарный минус меняет знак числа на противоположный. Унарный плюс су¬ществует «для симметрии», хотя и не производит никаких действий.
Автоувеличение и автоуменьшение
В Java, как и в С, существует множество различных сокращений. Сокращения могут упростить написание кода, а также упростить или усложнить его чтение.
Два наиболее полезных сокращения — это операторы увеличения (инкре¬мента) и уменьшения (декремента) (также часто называемые операторами ав¬томатического приращения и уменьшения). Оператор декремента записывается в виде — и означает «уменьшить на единицу». Оператор инкремента обознача¬ется символами ++ и позволяет «увеличить на единицу». Например, если пере¬менная а является целым числом, то выражение ++а будет эквивалентно (а = а + 1). Операторы инкремента и декремента не только изменяют перемен¬ную, но и устанавливают ей в качестве результата новое значение.
Каждый из этих операторов существует в двух версиях — префиксной и постфиксной. Префиксный инкремент значит, что оператор ++ записывается перед переменной или выражением, а при постфиксном инкременте оператор следует после переменной или выражения. Аналогично, при префиксном дек¬ременте оператор — указывается перед переменной или выражением, а при
постфиксном — после переменной или выражения. Для префиксного инкре¬мента и декремента (то есть ++а и —а) сначала выполняется операция, а затем выдается результат. Для постфиксной записи (а++ и а—) сначала выдается зна¬чение, и лишь затем выполняется операция. Например:
// operators/AutoInc java
import static net mindview util Print *.
public class Autolnc {
i); + ++i) + i++) i). + --i) + i-) i),
// Префиксный инкремент
// Постфиксный инкремент
// Префиксный декремент
// Постфиксный декремент
public static void main(String[] args) { int i = 1; printC'i : print("++i print("i++ printC'i • print C'--i printC'i-- printC'i
} /* Output- i . 1 ++i • 2 i++ . 2 i . 3 -i . 2 1-- 2
i • 1 *///.-
Вы видите, что при использовании префиксной формы результат получает¬ся после выполнения операции, тогда как с постфиксной формой он доступен до выполнения операции. Это единственные операторы (кроме операторов при¬сваивания), которые имеют побочный эффект. (Иначе говоря, они изменяют свой операнд вместо простого использования его значения.)
Оператор инкремента объясняет происхождение названия языка С++; под¬разумевается «шаг вперед по сравнению с С». В одной из первых речей, посвя¬щенных Java, Билл Джой (один из его создателей) сказал, что «Java=C++—» («Си плюс плюс минус минус»). Он имел в виду, что Java — это С++, из кото¬рого убрано все, что затрудняет программирование, и поэтому язык стал гораз¬до проще. Продвигаясь вперед, вы увидите, что отдельные аспекты языка, ко¬нечно, проще, и все же Java не настолько проще С++.
Операторы сравнения
Операторы сравнения выдают логический (boolean) результат. Они проверяют, в каком отношении находятся значения их операндов. Если условие проверки истинно, оператор выдает true, а если ложно — false. К операторам сравнения относятся следующие: «меньше чем» (<), «больше чем» (>), «меньше чем или равно» (<=), «больше чем или равно» (>=), «равно» (==) и «не равно» (!=). «Рав¬но» и «не равно» работают для всех примитивных типов данных, однако ос¬тальные сравнения не применимы к типу boolean.
Проверка объектов на равенство
Операции отношений == и != также работают с любыми объектами, но их смысл нередко сбивает с толку начинающих программистов на Java. Пример:
//: operators/AutoInc.java
public class Equivalence {
public static void main(String[] args) { Integer nl = new Integer(47); Integer n2 = new Integer(47); System.out.println(nl == n2); System out println(nl != n2);
}
} /* Output.
false
true
*///:-
Выражение System.out.println(nl == n2) выведет результат логического срав¬нения, содержащегося в скобках. Казалось бы, в первом случае результат дол¬жен быть истинным (true), а во втором — ложным (false), так как оба объекта типа Integer имеют одинаковые значения. Но в то время как содержимое объек¬тов одинаково, ссылки на них разные, а операторы != и == сравнивают именно ссылки. Поэтому результатом первого выражения будет false, а второго — true. Естественно, такие результаты поначалу ошеломляют.
А если понадобится сравнить действительное содержимое объектов? При¬дется использовать специальный метод equals(), поддерживаемый всеми объек¬тами (но не примитивами, для которых более чем достаточно операторов == и !=). Вот как это делается:
//: operators/EqualsMethod.java
public class EqualsMethod {
public static void main(String[] args) { Integer nl = new Integer(47); Integer n2 = new Integer(47); System.out.println(nl.equal s(n2));
}
} /* Output:
true
*///:-
На этот раз результат окажется «истиной» (true), как и предполагалось. Но все не так просто, как кажется. Если вы создадите свой собственный класс вроде такого:
//: operators/EqualsMethod2 java
// Метод equals() по умолчанию не сравнивает содержимое
class Value { int i;
}
public class EqualsMethod2 {
public static void main(String[] args) {
Value vl = new ValueO.
Value v2 = new ValueO.
vl.i = v2 i = 100;
System out println(vl equals(v2));
}
} /* Output false *///.-
мы вернемся к тому, с чего начали: результатом будет false. Дело в том, что ме¬тод equals() по умолчанию сравнивает ссылки. Следовательно, пока вы не пере¬определите этот метод в вашем новом классе, не получите желаемого результа¬та. К сожалению, переопределение будет рассматриваться только в главе 8, а пока осторожность и общее понимание принципа работы equals() позволит из¬бежать некоторых неприятностей.
Большинство классов библиотек Java реализуют метод equals() по-своему, сравнивая содержимое объектов, а не ссылки на них.
Логические операторы
Логические операторы И (&&), ИЛИ (||) и НЕ (!) производят логические значе¬ния true и false, основанные на логических отношениях своих аргументов. В следующем примере используются как операторы сравнения, так логические операторы:
//: operators/Bool Java
// Операторы сравнений и логические операторы.
import java.util.*;
import static net.mindview.util.Print.*;
public class Bool {
public static void main(String[] args) { Random rand = new Random(47); int i = rand.nextlnt(lOO): int j = rand.nextlnt(lOO); printC'i = " + i); printC'j = " + J): printC'i > j is " + (i > j)); printC'i < j is " + (i < j)); printC'i >= j is " + (i >= j)); printC'i <= j is " + (i <= j)); printC'i == j is " + (i == j)); printC'i != j is " + (i != j)); // В Java целое число (int) не может // интерпретироваться как логический тип (boolean) //! printC'i && j is " + (i && j)); //! printC'i || j is " + (i || j)); //! printC!i is " + !i); printed < 10) && (j < 10) is "

Report Page