Ответ 1
После того, как первый a++
a
станет 4. Таким образом, у вас есть 3 * 4 = 12
.
(a
становится 5 после второго a++
, но это отбрасывается, поскольку присваивание a =
отменяет его)
Я изучаю экзамен 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);
После того, как первый a++
a
станет 4. Таким образом, у вас есть 3 * 4 = 12
.
(a
становится 5 после второго a++
, но это отбрасывается, поскольку присваивание a =
отменяет его)
Ваше выражение:
a += (a++) * (a++);
эквивалентно любому из них:
a = a*a + 2*a
a = a*(a+2)
a += a*(a+1)
Используйте любой из них.
a++
означает "значение a, а a затем увеличивается на 1". Поэтому, когда вы запускаете
(a++) * (a++)
сначала оценивается первая a++
и выдает значение 3. a
затем увеличивается на 1. Затем вычисляется второй a++
. a
выводит значение 4 и затем снова увеличивается (но теперь это не имеет значения)
Итак, это превращается в
a = 3 * 4
что равно 12.
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
на третьем шаге, а правая сторона - 12
. Поэтому он назначает 3 + 12 = 15 на a
.a
равно 15.Здесь следует отметить, что приоритет оператора не оказывает прямого влияния на порядок оценки. Это влияет только на форму дерева и, следовательно, косвенно на порядок. Но среди братьев и сестер в дереве оценка всегда слева направо, независимо от приоритета оператора.
(a++)
- это приращение, поэтому значение выражения равно 3.
(a++)
- это приращение, поэтому значение выражения теперь равно 4.
Оценка выражений происходит слева направо.
3 * 4 = 12
Каждый раз, когда вы используете ++, вы добавляете post-incrementing a. Это означает, что первый a ++ оценивает значение 3, а второй оценивает до 4. 3 * 4 = 12.
Существует общее отсутствие понимания того, как работают операторы. Честно говоря, каждый оператор является синтаксическим сахаром.
Все, что вам нужно сделать, это понять, что на самом деле происходит за каждым оператором. Предположим следующее:
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))
Это, конечно, более подробно, но сразу становится очевидным, что вы никогда не хотите выполнять более двух операций в одной строке.
В случае:
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
В случае:
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
Главное, чтобы отметить здесь, что в этом случае компилятор решает слева направо и в случае поэтапного приращения, значение до инкремента используется в вычислении, и при перемещении слева направо используется увеличиваемое значение.
(a++)
означает return a
и increment, поэтому
(a++) * (a++)
означает 3 * 4
Вот код 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!
Это 12. Выражение начинает оцениваться слева. Так оно и делает:
a = (3++) * (4++);
После вычисления первой части (3 ++) a равно 4, поэтому в следующей части она делает a = 3 * 4 = 12. Обратите внимание, что последний пост-инкремент (4 ++) выполняется, но не имеет эффекта, поскольку после этого ему присваивается значение 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
Просто, чтобы убедиться, где положить выражение ++
, которое изменяет значение на основе местоположения.
Каждый четко объяснил первое выражение и почему значение a равно 12.
Для ответа на вопрос, ответ абсолютно очевиден для случайного наблюдателя:
17
Если вы используете ++, то в следующий раз, когда вы используете a, он увеличивается на единицу. Итак, вы делаете
a = 3 * (3 + 1) = 3 * 4 = 12
Приращения pre и post-prefix имеют более высокий приоритет, чем оператор умножения. поэтому выражение оценивается как 3 * 4.