Java中的逻辑操作顺序令人困惑

问题描述 投票:0回答:3

我从测验中得到了一个操作顺序问题,但解释并不完全有用。这是代码:

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;

[在postfix之后,优先级给予前缀]。

((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 ++是的,这是有道理的。但我认为&&在||之前。

java operator-precedence short-circuiting
3个回答
0
投票
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 

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和短路,我们可以说a || b && c没有组合成(a || b) && c


0
投票

最后当(((a ++)== 2)|| false)[a = 1]然后作为||运算符的优先级低于++,所以这里a将变为3 ..然后它将打印a = 3虽然它是一个短路运算符仍然必须执行++运算符1st。

© www.soinside.com 2019 - 2024. All rights reserved.