Java中的逻辑操作顺序混乱

时间:2019-03-13 02:47:51

标签: java operator-precedence short-circuiting

我从一个测验中有一个操作顺序问题,并且说明并没有帮助。这是代码:

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]

???? 另一点是答案键说先做a ++,然后||。下一个。是的,是的。但是我认为&&在||之前。

2 个答案:

答案 0 :(得分:2)

Java Language Specification

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,因此不会计算第三个表达式。但是没有违反优先级规则。我希望这可以消除任何混乱。如果没有,我很乐意继续在聊天中讨论并更新我的答案。因为我们从原始代码中知道,如果第一个表达式为true,则||返回true并发生短路,因此可以说a || b && c没有组合到(a || b) && c中。

答案 1 :(得分:0)

最后,当((((a ++)== 2)|| false )[a = 1] 然后做为||运算符的优先级低于++,因此这里a将变为3 ..然后它将打印a = 3 尽管它是短路运算符,但仍然必须首先执行++运算符。