«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 будет по порядку:

Далее, когда левый операнд является массивом, шаги немного отличаются:

  1. Verify the operand is a declared variable
  2. Save the value of the left-hand operand
  3. Evaluate the right-hand operand
  4. Perform the binary operation as indicated by the compound operator
  5. Convert the result of the binary operation to the type of the left-hand variable (implicit casting)
  6. Assign the converted result to the left-hand variable

Если какой-либо шаг оценки завершается неудачно, Java не продолжает выполнять следующие шаги.

  1. Verify the array expression on the left-hand side and throw a NullPointerException or ArrayIndexOutOfBoundsException if it’s incorrect
  2. Save the array element in the index
  3. Evaluate the right-hand operand
  4. 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.

«