Подтвердить что ты не робот

A = (a ++) * (a ++) дает странные результаты в Java

Я изучаю экзамен OCPJP, и поэтому я должен понимать каждую маленькую странную деталь Java. Это включает в себя порядок, в котором операторы pre и post-increment применяются к переменным. Следующий код дает мне странные результаты:

int a = 3;

a = (a++) * (a++);

System.out.println(a); // 12

Не должен ли быть ответ? Или, может быть, 13? Но не 12!

ПОСЛЕДУЮЩИЙ:

Каков результат следующего кода?

int a = 3;

a += (a++) * (a++);

System.out.println(a);
4b9b3361

Ответ 1

После того, как первый a++ a станет 4. Таким образом, у вас есть 3 * 4 = 12.

(a становится 5 после второго a++, но это отбрасывается, поскольку присваивание a = отменяет его)

Ответ 2

Ваше выражение:

a += (a++) * (a++);

эквивалентно любому из них:

a = a*a + 2*a
a = a*(a+2)
a += a*(a+1)

Используйте любой из них.

Ответ 3

a++ означает "значение a, а a затем увеличивается на 1". Поэтому, когда вы запускаете

(a++) * (a++)

сначала оценивается первая a++ и выдает значение 3. a затем увеличивается на 1. Затем вычисляется второй a++. a выводит значение 4 и затем снова увеличивается (но теперь это не имеет значения)

Итак, это превращается в

a = 3 * 4

что равно 12.

Ответ 4

int a = 3;
a += (a++) * (a++);

Сначала построим дерево синтаксиса:

+=
  a
  *
    a++
    a++

Чтобы оценить это, начинайте с внешнего элементарного элемента и спуска рекурсивно. Для каждого элемента do:

  • Оценить детей слева направо
  • Оценить сам элемент

Оператор += является специальным: он расширяется до значения left = left + right, но только оценивает выражение left один раз. Тем не менее левая сторона оценивается как значение (а не только переменная), прежде чем правая сторона будет оценена до значения.

Это приводит к:

  • Начните оценивать +=
  • Оцените левую сторону присвоения переменной a.
  • Оцените переменную a значением 3, которое будет использоваться в добавлении.
  • Начать оценку *
  • Оцените первый a++. Это возвращает текущее значение a 3 и устанавливает a в 4
  • Оцените второй a++. Это возвращает текущее значение a 4 и устанавливает a в 5
  • Рассчитать произведение: 3 * 4 = 12
  • Выполнить +=. Левая сторона была оценена на 3 на третьем шаге, а правая сторона - 12. Поэтому он назначает 3 + 12 = 15 на a.
  • Конечное значение a равно 15.

Здесь следует отметить, что приоритет оператора не оказывает прямого влияния на порядок оценки. Это влияет только на форму дерева и, следовательно, косвенно на порядок. Но среди братьев и сестер в дереве оценка всегда слева направо, независимо от приоритета оператора.

Ответ 5

(a++) - это приращение, поэтому значение выражения равно 3.

(a++) - это приращение, поэтому значение выражения теперь равно 4.

Оценка выражений происходит слева направо.

3 * 4 = 12 

Ответ 6

Каждый раз, когда вы используете ++, вы добавляете post-incrementing a. Это означает, что первый a ++ оценивает значение 3, а второй оценивает до 4. 3 * 4 = 12.

Ответ 7

Существует общее отсутствие понимания того, как работают операторы. Честно говоря, каждый оператор является синтаксическим сахаром.

Все, что вам нужно сделать, это понять, что на самом деле происходит за каждым оператором. Предположим следующее:

a = b -> Operators.set(a, b) //don't forget this returns b
a + b -> Operators.add(a, b)
a - b -> Operators.subtract(a, b)
a * b -> Operators.multiply(a, b)
a / b -> Operators.divide(a, b)

Сложные операторы затем могут быть переписаны с использованием этих обобщений (пожалуйста, для простоты проигнорируйте типы возврата):

Operators.addTo(a, b) { //a += b
  return Operators.set(a, Operators.add(a, b));
}

Operators.preIncrement(a) { //++a
  return Operators.addTo(a, 1);
}

Operators.postIncrement(a) { //a++
  Operators.set(b, a);
  Operators.addTo(a, 1);
  return b;
}

Вы можете переписать свой пример:

int a = 3;
a = (a++) * (a++);

а

Operators.set(a, 3)
Operators.set(a, Operators.multiply(Operators.postIncrement(a), Operators.postIncrement(a)));

Что можно разделить с помощью нескольких переменных:

Operators.set(a, 3)
Operators.set(b, Operators.postIncrement(a))
Operators.set(c, Operators.postIncrement(a))
Operators.set(a, Operators.multiply(b, c))

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

Ответ 8

В случае:

int a = 3;  
a = (a++) * (a++); 

a = 3 * a++; now a is 4 because of post increment
a = 3 * 4; now a is 5 because of second post increment
a = 12; value of 5 is overwritten with 3*4 i.e. 12 

следовательно, мы получаем выход как 12.

В случае:

a += (a++) * (a++); 
a = a + (a++) * (a++);
a = 3 + (a++) * (a++); // a is 3
a = 3 + 3 * (a++); //a is 4
a = 3 + 3 * 4; //a is 5
a = 15

Главное, чтобы отметить здесь, что в этом случае компилятор решает слева направо и в случае поэтапного приращения, значение до инкремента используется в вычислении, и при перемещении слева направо используется увеличиваемое значение.

Ответ 9

(a++) означает return a и increment, поэтому (a++) * (a++) означает 3 * 4

Ответ 10

Вот код java:

int a = 3;
a = (a++)*(a++);

Вот байт-код:

  0  iconst_3
  1  istore_1 [a]
  2  iload_1 [a]
  3  iinc 1 1 [a]
  6  iload_1 [a]
  7  iinc 1 1 [a]
 10  imul
 11  istore_1 [a]

Вот что происходит:

Вставляет 3 в стек, затем выталкивает 3 из стека и сохраняет его в точке. Теперь a = 3, и стек пуст.

  0  iconst_3
  1  istore_1 a

Теперь он выталкивает значение из "a" (3) в стек и затем увеличивает (3 → 4).

  2  iload_1 [a]
  3  iinc 1 1 [a]

Итак, теперь "a" равно "4", стек равен {3}.

Затем он снова загружает "a" (4), вставляет в стек и увеличивает "a" .

  6  iload_1 [a]
  7  iinc 1 1 [a]

Теперь "a" равно 5, а стек равен {4,3}

Таким образом, он, наконец, выдает два значения из стека (4 и 3), умножает и сохраняет его обратно в стек (12).

 10  imul

Теперь "a" равно 5, а стек равен 12.

Наконец, выталкивает 12 из стека и сохраняет в.

 11  istore_1 [a]

TADA!

Ответ 11

Это 12. Выражение начинает оцениваться слева. Так оно и делает:

a = (3++) * (4++);

После вычисления первой части (3 ++) a равно 4, поэтому в следующей части она делает a = 3 * 4 = 12. Обратите внимание, что последний пост-инкремент (4 ++) выполняется, но не имеет эффекта, поскольку после этого ему присваивается значение 12.

Ответ 12

Пример 1

int a = 3;

a = (++a) * (a++);

System.out.println(a); // 16

Пример 2

int a = 3;

a = (++a) * (++a);

System.out.println(a); // 20

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

Ответ 13

Каждый четко объяснил первое выражение и почему значение a равно 12.

Для ответа на вопрос, ответ абсолютно очевиден для случайного наблюдателя:

17

Ответ 14

Если вы используете ++, то в следующий раз, когда вы используете a, он увеличивается на единицу. Итак, вы делаете

a = 3 * (3 + 1) = 3 * 4 = 12

Ответ 15

Приращения pre и post-prefix имеют более высокий приоритет, чем оператор умножения. поэтому выражение оценивается как 3 * 4.