Запутан порядок операций с логикой в ​​Java - PullRequest
0 голосов
/ 13 марта 2019

У меня есть проблема порядка операций из викторины, и объяснение не совсем полезно.Вот код:

package com.udayan.oca;

public class Test {
     public static void main(String [] args) {
         int a = 2;
         boolean res = false;
         res = a++ == 2 || --a == 2 && --a == 2;
         System.out.println(a);
     }
}

Он говорит, что печатает 3, что он делает, потому что я проверял это, но я не понимаю, как.Вот их объяснение:

a++ == 2 || --a == 2 && --a == 2;

[Дано выражение].(a++) == 2 || --a == 2 && --a == 2;

[Postfix имеет более высокий приоритет, чем другие операторы].

(a++) == 2 || (--a) == 2 && (--a) == 2;

[После постфикса приоритет отдается префиксу].

((a++) == 2) || ((--a) == 2) && ((--a) == 2);

[== имеет более высокий приоритет над && и ||].

((a++) == 2) || (((--a) == 2) && ((--a) == 2));

[&& имеет более высокий приоритет над ||].

Давайте начнем решать: ((a++) == 2) || (((--a) == 2) && ((--a) == 2));

[a = 2, res = false].

(2 == 2) || (((--a) == 2) && ((--a) == 2));

[a = 3, res = false].true || (((--a) == 2) && ((--a) == 2));

[a = 3, res = false].

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

res - это истина, а a - 3.

Да, я понимаю, что короткое замыкание, кстати, нет необходимости объяснять это.

Итак, вот мое мышление:

res = a++ == 2 || --a == 2 && --a == 2 ->
(((a++) == 2) || (((--a) == 2) && ((--a) == 2))) [a = 2]

(((a++) == 2) || ((**1** == 2) && ((--a) == 2))) [a = 1]

(((a++) == 2) || (**false** && (**0** == 2))) [a = 1] //short-circuits

(((a++) == 2) || **false**) [a = 1] //short circuits

(**false**) [a = 1]

????Другой момент заключается в том, что ключ ответа говорит, что сначала нужно сделать ++, а затем ||следующий.А ++ Да, это имеет смысл.Но я думал, что && до ||

Ответы [ 3 ]

2 голосов
/ 13 марта 2019

Из спецификации языка Java ,

The conditional-or operator || operator is like | (§15.22.2), but evaluates its right-hand operand only if the value of its left-hand operand is false.

Итак, это проще, чем вы думаете. res = a++ == 2 || --a == 2 && --a == 2; оценивается так:

res = ((a++ == 2) || ((--a == 2) && (--a == 2)));

a++ == 2? Постинкремент означает, что a читается как 2 . Затем это выражение оценивается. 2 == 2, что правда. Короткое замыкание означает, что остальная часть выражения никогда не оценивается.

Итак, по сути, весь приведенный выше код - это res = a++ == 2;

Я сделал простую программу для проверки этого:

public class TestSOCode {
    public static void main(String [] args) {
        test1();
    }

    private static void test1(){
        int a = 2;
        boolean res = false;
        //res = a++ == 2 || --a == 2 && --a == 2;
        res = expression(a++, "One") || expression(--a, "Two") && expression(--a, "Three");
        System.out.println(res +" "+ a);
    }

    private static boolean expression(int i, String s){
        System.out.println(s+ " called with "+ i);
        return i == 2;
    }
}

Это дает результат

One called with 2
true 3

ОБНОВЛЕНИЕ: После некоторого обсуждения и исследования, я думаю, что было неправильное понимание разницы между приоритетом и порядком выполнения, когда речь идет о логических операторах.

res = a++ == 2 || --a == 2 && --a == 2;

Приоритет вышеприведенного оператора отрабатывается до его оценки. Я не буду переходить к другим правилам предшествования, так как это усложнит этот ответ, поэтому я упросту его:

res = x || y && z;

&& имеет приоритет, поэтому выражения сгруппированы так:

res = x || (y && z);

Как мы видим, && имеет приоритет, поэтому выражения слева и справа сгруппированы вместе, затем || вычисляется. Выражение слева от него - x, а выражение справа - (y && z) (я думаю, мы оба думали, что если бы приоритет был &&, это было бы похоже на (a || b) && c, поэтому сначала он будет оцениваться, но это не так, как это работает). Если мы хотим убедиться, что это действительно так, мы можем изменить приведенный выше код следующим образом:

 res = expression(a = 8, "One") || expression(a = 16, "Two") && expression(a = 32, "Three");

Это эквивалентно false || (false && false), но без какого-либо вмешательства компилятора в константы времени компиляции. Результат этого:

One called with 8
Two called with 16
false 16

Сначала оценивается ||, затем левая сторона &&. Это возвращает false, и false && ? всегда будет false, поэтому третье выражение не оценивается. Но никакие правила предшествования не были нарушены. Я надеюсь, что это прояснило любую путаницу. Если нет, я с удовольствием продолжу обсуждение в чате и обновлю свой ответ. Поскольку из исходного кода мы знаем, что если первое выражение истинно, || возвращает истину и короткие замыкания, мы можем сказать, что a || b && c не сгруппированы в (a || b) && c.

0 голосов
/ 13 марта 2019

В конце концов, когда (((a ++) == 2) || false ) [a = 1] Делается тогда как || оператор имеет меньший приоритет, чем ++, поэтому здесь a станет 3 .. тогда он выведет a = 3 Хотя это оператор короткого замыкания, он все равно должен выполнять оператор ++ 1-й.

0 голосов
/ 13 марта 2019
res = a++ == 2 || --a == 2 && --a == 2 (res is true)

1. a++ (post-increment, no) -> a = a + 1 -> it's still 2 -> when true -> it becomes 3
2. --a (pre-increment, right to left) -> a - 1 = a -> 1
3. --a (pre-increment, right to left) -> a - 1 = a -> 0 (its because of logical and, it never execute this part) 
4. == (equality, left to right) -> 2 == 2 || 1 == 2 && 0 == 2 -> true || false && false
5. && (logical and, left to right) -> false -> no more steps 
6. || (logical or, left to right) -> true -> go to 1.

// so take 3
// moral of the story is always use paranthesis
// op is correct for short-circuit 
...