a = (a++) * (a++) дает странные результаты в Java [закрыто]
Я учусь на экзамен OCPJP, и поэтому я должен понять каждую маленькую странную деталь Java. Это включает порядок, в котором операторы pre - и post-increment применяются к переменным. Следующий код дает мне странные результаты:
int a = 3;
a = (a++) * (a++);
System.out.println(a); // 12
разве ответ не должен быть 11? Или, может, 13? Но не 12!
ПОСЛЕДУЮЩИЕ ДЕЙСТВИЯ:
каков результат следующего кода?
int a = 3;
a += (a++) * (a++);
System.out.println(a);
15 ответов
после первый a++
a
будет 4. Так у вас есть 3 * 4 = 12
.
(a
становится 5 после 2-го 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++
чтобы оценить его, начните с внешнего элемента most и спуска рекурсивно. Для каждого элемента сделайте:
- оценивать детей слева направо
- оценить сам элемент
на +=
оператор особенный: он расширяется до чего-то вроде left = left + right
, но только вычисление выражения left
раз. Тем не менее, левая сторона оценивается к значению (а не только переменной), прежде чем правая сторона будет оценена в значение.
это приводит к:
- запустить оценке
+=
- оценить левую сторону присвоения переменной
a
. - оцените переменную
a
стоимостью3
, который будет использоваться в дополнение. - запустить оценке
*
- оценить первый
a++
. Это возвращает текущее значение3
и устанавливаетa
to4
- оценить второй
a++
. Это возвращает текущее значение4
и телеаппаратурыa
to5
- рассчитать продукт: 3*4 = 12
- выполнить
+=
. Левая сторона была оценена на3
на третьем шаге и правой стороне12
. Таким образом, он присваивает 3+12=15a
. - конечное значение
a
- это 15.
здесь следует отметить, что оператор приоритет не оказывает прямого влияния на порядок оценки. Она влияет только на форму дерева, а значит, косвенно и на порядок. Но среди братьев и сестер в дереве оценка всегда слева направо, независимо от приоритета оператора.
(a++)
является шагом post, поэтому значение выражения равно 3.
(a++)
является шагом post, поэтому значение выражения теперь равно 4.
оценка выражения происходит слева направо.
3 * 4 = 12
каждый раз, когда вы используете a++, вы постинкрементируете 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++);
as
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
следовательно, мы получаем выход как 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
главное отметить, что в этом случае компилятор решает слева направо и в случае post increment, значение перед инкрементом используется в расчете и при движении слева направо используется инкрементное значение.
вот код 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. Теперь a = 3 и стек пуст.
0 iconst_3
1 istore_1 a
теперь он выталкивает значение из " a " (3) в стек, а затем увеличивает a (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}
таким образом, он, наконец, всплывает два значения fisrt из стека (4 и 3), умножает и сохраняет его обратно в стек (12).
10 imul
теперь " a " равно 5, а стек равен 12.
наконец, это pops 12 из стека и магазины на.
11 istore_1 [a]
Тада!
Это 12. Выражение начинает оценивать слева. Так оно и есть:
a = (3++) * (4++);
Как только первая часть (3++) оценивается, a равно 4, поэтому в следующей части он делает a = 3*4 = 12. Обратите внимание, что последний post-increment (4++) выполняется, но не имеет эффекта, так как после этого a присваивается значение 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
приращения до и после префикса имеют более высокий приоритет, чем оператор умножения. отсюда и выражение оценивается как 3*4.
Если вы используете a++ в следующий раз, когда вы используете a, он увеличивается на единицу. Так что твои дела
a = 3 * (3 + 1) = 3 * 4 = 12