«1. Обзор
В этом руководстве мы рассмотрим составные операторы Java, их типы и то, как Java их оценивает.
Мы также объясним, как работает неявное приведение типов.
2. Составные операторы присваивания
Оператор присваивания — это бинарный оператор, который присваивает результат правой части переменной в левой части. Самым простым является оператор присваивания «=»:
int x = 5;
Этот оператор объявляет новую переменную x, присваивает x значение 5 и возвращает 5.
Составные операторы присваивания — это более короткий способ применения оператора присваивания. арифметическую или побитовую операцию и присвоить значение операции переменной в левой части.
Например, следующие два оператора умножения эквивалентны, то есть a и b будут иметь одно и то же значение:
int a = 3, b = 3, c = -2;
a = a * c; // Simple assignment operator
b *= c; // Compound assignment operator
Важно отметить, что переменная в левой части составного оператора присваивания уже должна быть объявлено. Другими словами, составные операторы нельзя использовать для объявления новой переменной.
Как и оператор присваивания «=», составные операторы возвращают присвоенный результат выражения:
long x = 1;
long y = (x+=2);
И x, и y будут содержать значение 3.
Присваивание (x+=2) делает две вещи: во-первых, добавляет 2 к значению переменной x, которое становится равным 3; во-вторых, возвращает значение присваивания, которое также равно 3.
3. Типы составных операторов присваивания
Java поддерживает 11 составных операторов присваивания. Мы можем сгруппировать их в арифметические и побитовые операторы.
Давайте пройдемся по арифметическим операторам и операциям, которые они выполняют:
-
Приращение: += Декремент: -= Умножение: *= Деление: /= Модуль: %=
Затем у нас также есть побитовые операторы:
-
И, двоичный: \u0026= Исключающее ИЛИ, двоичный: ^= Включающий ИЛИ, двоичный: |= Сдвиг влево, двоичный: \u003c\u003c= Сдвиг вправо, двоичный: \u003e\u003e= Сдвиг вправо, заполнение нулями: \u003e\u003e\u003e= ~~ ~ Давайте посмотрим на несколько примеров этих операций:
Как мы видим здесь, синтаксис для использования этих операторов согласован.
// Simple assignment
int x = 5; // x is 5
// Incrementation
x += 5; // x is 10
// Decrementation
x -= 2; // x is 8
// Multiplication
x *= 2; // x is 16
// Modulus
x %= 3; // x is 1
// Binary AND
x &= 4; // x is 0
// Binary exclusive OR
x ^= 4; // x is 4
// Binary inclusive OR
x |= 8; // x is 12
4. Оценка составных операций присваивания
В Java есть два способа оценки составных операций.
Во-первых, когда левый операнд не является массивом, тогда Java будет по порядку:
Далее, когда левый операнд является массивом, шаги немного отличаются:
- Verify the operand is a declared variable
- Save the value of the left-hand operand
- Evaluate the right-hand operand
- Perform the binary operation as indicated by the compound operator
- Convert the result of the binary operation to the type of the left-hand variable (implicit casting)
- Assign the converted result to the left-hand variable
Если какой-либо шаг оценки завершается неудачно, Java не продолжает выполнять следующие шаги.
- Verify the array expression on the left-hand side and throw a NullPointerException or ArrayIndexOutOfBoundsException if it’s incorrect
- Save the array element in the index
- Evaluate the right-hand operand
- Check if the array component selected is a primitive type or reference type and then continue with the same steps as the first list, as if the left-hand operand is a variable.
Давайте приведем несколько примеров, связанных с оценкой этих операций над элементом массива:
Как и следовало ожидать, это вызовет исключение NullPointerException.
int[] numbers = null;
// Trying Incrementation
numbers[2] += 5;
Однако, если мы присвоим массиву начальное значение:
Мы избавимся от исключения NullPointerException, но все равно получим исключение ArrayIndexOutOfBoundsException, поскольку используемый индекс неверен.
int[] numbers = {0, 1};
// Trying Incrementation
numbers[2] += 5;
Если мы это исправим, операция завершится успешно:
Наконец, переменная x будет равна 6 в конце присваивания.
int[] numbers = {0, 1};
// Incrementation
numbers[1] += 5; // x is now 6
5. Неявное приведение типов
Одна из причин, по которой составные операторы полезны, заключается в том, что они не только обеспечивают более короткий путь для операций, но и неявно приводят переменные.
Формально составное выражение присваивания вида:
E1 op= E2
эквивалентно:
E1 – (T)(E1 op E2)
где T — тип Е1.
Давайте рассмотрим следующий пример:
Давайте рассмотрим, почему последняя строка не компилируется.
long number = 10;
int i = number;
i = i * number; // Does not compile
Java автоматически продвигает меньшие типы данных к более крупным, когда они находятся вместе в операции, но выдает ошибку при попытке преобразования из более крупных типов в меньшие.
Итак, сначала я буду повышен до длинной, а затем умножение даст результат 10L. Длинный результат будет присвоен i, который является целым числом, и это вызовет ошибку.
Это можно исправить с помощью явного приведения:
Операторы составного присваивания в Java идеально подходят в этом случае, потому что они выполняют неявное приведение:
i = (int) i * number;
Этот оператор отлично работает, приводя результат умножения в int и присвоение значения левой переменной, т.е.
i *= number;
6. Заключение
«В этой статье мы рассмотрели составные операторы в Java, приведя несколько примеров и их различные типы. Мы объяснили, как Java оценивает эти операции.
Наконец, мы также рассмотрели неявное приведение типов — одну из причин, по которым эти сокращенные операторы полезны.
Как всегда, все фрагменты кода, упомянутые в этой статье, можно найти в нашем репозитории GitHub.
«