`

关于 &&和||的一个表达式A&&B||C&&D的运算顺序

阅读更多

       对于表达式A && B || C && D, 一般我们认为可能有两种执行顺序(A && B)|| (C && D), 即先执行A && B 的判断,然后执行C && D的判断,最后再执行||的判断(当然这是没有考虑Java中"短路"的一般执行顺序(后面结果的验证就是根据"短路"的特性))

另外一种可能就是((A && B) || C) && D, 即先执行A && B的判断,将结果作为一个参数再与C进行或运算,最后再与D进行与运算。

分析:

首先介绍下Java的短路特性。

对于&&,如果左边的参数为false的话,那么就不会再去判断右边参数的真假而直接返回false;

对于||,如果左边的参数为true的话,那么就不会再去判断右边参数的真假而直接返回true。

下面是一个简单的示例简单了解下短路的概念: 

public class Testcc {  
    private static int counter = 0;  
    private final int id = counter++;  
    public boolean test(boolean a) {  
        if(a)   
            System.out.println("执行了" + id);  
        return a;  
    }  
    public static void main(String[] args) {  
        Testcc tt0 = new Testcc();  
        Testcc tt1 = new Testcc();  
        Testcc tt2 = new Testcc();  
        Testcc tt3 = new Testcc();  
        Testcc tt4 = new Testcc();  
        Testcc tt5 = new Testcc();  
        Testcc tt6 = new Testcc();  
        Testcc tt7 = new Testcc();  
        // A && B   
        System.out.println("***** test A && B *****");  
        System.out.println(tt0.test(true) && tt1.test(true));  
        System.out.println(tt2.test(false) && tt3.test(true));  
        // A || B  
        System.out.println("***** test A || B *****");  
        System.out.println(tt4.test(true) || tt5.test(true));  
        System.out.println(tt6.test(false) || tt7.test(true));  
    }  
}  
// 输出结果如下: 
***** test A && B ***** 
执行了0  
执行了1  
true  
false  
***** test A || B *****  
执行了4  
true  
执行了7  
true  
完全符合我们上面的说法。 

下面接着我们的思路往下说:

public class Testaa {  
    public static void show() {  
        boolean a = true;  
        boolean b = true;  
        boolean c = true;  
        boolean d = false;  
        System.out.println(test(a)&&test(b)||test(c)&&test(d));  
    }  
    public static boolean test(boolean d) {  
        if (d) {  
            System.out.println("d");  
        }  
        return d;  
    }  
    public static void main(String[] args) {  
        show();  
    }  
}  

按照第一种可能,如果 A && B为true的话,那么C && D就不会再执行了,那就只会输出两个d和最终的结果true; 

按照第二种可能,A && B 为true,那么将不必执行和C的或运算,但是和D的与运算会执行; 因为d为false, 所以仍是输出两个d, 但结果为false。

请看输出结果: 

d 
d 
true

正好验证了我们第一个猜想。即按照(A && B)||(C && D)的顺序运算。

下面是将上面的文件使用javap进行反汇编之后的结果:

Compiled from "Testaa.java"  
public class Testaa extends java.lang.Object{  
public Testaa();  
    // ...  
public static void show();  
  Code:  
   0:   iconst_1  
   1:   istore_0  
   2:   iconst_1  
   3:   istore_1  
   4:   iconst_1  
   5:   istore_2  
   6:   iconst_0  
   7:   istore_3  
   8:   getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;  
   11:  iload_0  
   12:  invokestatic    #3; //Method test:(Z)Z  
   15:  ifeq    25  
   18:  iload_1  
   19:  invokestatic    #3; //Method test:(Z)Z  
   22:  ifne    39  
   25:  iload_2  
   26:  invokestatic    #3; //Method test:(Z)Z  
   29:  ifeq    43  
   32:  iload_3  
   33:  invokestatic    #3; //Method test:(Z)Z  
   36:  ifeq    43  
   39:  iconst_1  
   40:  goto    44  
   43:  iconst_0  
   44:  invokevirtual   #4; //Method java/io/PrintStream.println:(Z)V  
   47:  return  
  
public static boolean test(boolean);  
  Code:  
   0:   iload_0  
   1:   ifeq    12  
   4:   getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;  
   7:   ldc #5; //String d  
   9:   invokevirtual   #6; //Method java/io/PrintStream.println:(Ljava/lang/String;)V  
   12:  iload_0  
   13:  ireturn  
  
public static void main(java.lang.String[]);  
  //...  
} 
 
//主要JVM指令介绍  
ifeq: 当栈顶int型数值等于0时跳转  
ifne: 当栈顶int型数值不等于0时跳转

下面是我个人的理解,请大家参考:

根据上面的结果可以发现:iconst_0表示false; iconst_1表示true; 

我们从第15行(红色的行号)看起:

1 先判断第一个参数是否为false,

  1.1 若为false, 直接跳转到25行; 

    1.1.1 判断第三个参数是否为false; 

       a) 若为false, 则跳转43行,取iconst_0(true)的值作为整个结果的返回值;

       b) 若为true, 则去判断第四个参数;

      1.1.1.1判断第四个参数是否为false;

       a) fasle, 则跳转到第43行,然后同前面的a);

       b) true, 取常量iconst_1(true)的值作为整个结果的返回值.

  1.2 若为true, 接着去判断第二个参数是否为true(注意是ifne是不为0则跳转);

       a) 若为true, 则跳转39行, 取iconst_1的值作为整个结果的返回值。

       b) 若为false, 则去判断第三个参数, 接着就是上面说的了。

从这也可以看出他的执行就是第一种。

 

疑问:但是为什么会是这样的运算顺序,还需要进一步思考。

解答:这是和运算符的优先级和结合顺序有关。查看了Java运算符的特性可以发现,&&的优先级高于||,并且是左结合,所以才有了上面的结果。

 

下面附上Java运算符的介绍:

 






 



 

 

还有一个问题,boolean类型的变量是以整数类型存储的?

个人看法:对于一个程序员来说,编写出的代码在保证功能和效率性能的基础上应该尽可能的实现简洁清晰易懂,这样对于别人理解代码以及后期维护都很有利。

以上就是这个问题的所有内容,如果有说的不对的地方,恳请大家能够批评指正,谢谢。

 

  • 大小: 19.8 KB
  • 大小: 15.4 KB
  • 大小: 6.7 KB
分享到:
评论

相关推荐

    C语言_顺序分支结构_选择题新.doc

    表达式 a||b+c&&b-c 的值不为 0,因为 a||b+c&&b-c 是一个逻辑或运算,且 a||b+c&&b-c 的值不为 0。 表达式 !((a<b)&&!c||1) 的值为 0,因为 !((a<b)&&!c||1) 是一个逻辑非运算,且 ((a<b)&&!c||1) 的值为 1。 ...

    C语言中的运算符和表达式

    例如,`(a > b) && (c < d)` 表示如果`a`大于`b`并且`c`小于`d`,则整个表达式的值为真。 4. **位操作运算符**:针对二进制位进行操作,包括位与(&)、位或(|)、位非(~)、位异或(^)、左移()、右移(>>)。...

    谢丽聪老师C语言分支结构程序PPT学习教案.pptx

    b) == c || (d < a)`,`a + b > c && x + y < b` 等同于 `((a + b) > c) && ((x + y) < b)`。 通过示例进一步解释: 1. 当 `x = 0`, `y = 2`, `a = 8`, `k = -1`, `q = 1`, `z = 1` 时,表达式 `x + y > 3 && a == ...

    顺序结构域逻辑运算C语言

    顺序结构域逻辑运算C语言实验报告 本实验报告的主要目标是掌握顺序结构程序的编写和调试方法,熟悉逻辑运算符和逻辑表达式的使用,并学会基本的调试程序方法。 实验目的和要求: 1. 掌握数据输入/输出函数的使用...

    关于短路运算,关于短路运算

    则大多数情况下,由于A为真,所以不会计算B和C,从而提高了效率。 ### 短路运算符的行为 - **&& 运算符**:对于表达式`A && B`: - 如果A为假,则整个表达式的结果为假,不会计算B。 - 如果A为真,则计算B来确定...

    栈和队列的应用实验 利用栈实现中缀表达式与前缀表达式的转换

    相对应的还有前缀表达式(Prefix Notation),如:"+ - A * B C D",转换成中缀表达式为:"A - B * C + D";后缀表达式 (Postfix Notation),比如前所述的中缀表达式转换为后缀表达式为:"A B C * - D +"。 四、...

    C语言知识点,期末,例题

    在C语言中,逻辑运算符`&&`和`||`的优先级是最低的,这意味着它们在表达式中的运算顺序是最后进行的。这一特性对于理解复杂的逻辑判断非常重要。 - **&& 运算符**:表示逻辑“与”,当两边的表达式都为真时,结果才...

    C语言习题huizong.pdf

    例如,输入语句`scanf("a=%d,b=%d,c=%d", &a, &b, &c)`期望用户输入形如`a=1,b=2,c=3`的格式。 在C语言中,变量命名有一些规则,如不能以数字开头,不能使用保留关键字,如`if`、`case`等,合法的标识符可以包含...

    第04章:运算符和算术表达式

    例如,`(a + b) * (c - d)` 是一个包含加法、减法和乘法的复杂算术表达式。C#会根据运算符的优先级和结合性来计算这些表达式。 在C#中,运算符的优先级很重要,它决定了哪些操作先进行。通常,乘法和除法的优先级...

    C语言序列点总结

    序列点是C语言中的一个重要概念,它指的是程序运行中的一个特殊时间点,在该点之前的所有副作用已经结束,并且后续的副作用还没发生,而两个序列点之间所有的表达式或代码执行顺序是未定义的。 副作用是指对数据...

    C语言程序设计标准教程

    比较详实 第三章: C语言程序设计初步 C语言程序设计 本课介绍C语言程序设计的基本方法...&是一个取地址运算符,&a是一个表达式,其功能是求变量的地址。 void main(){ int a,b,c; printf("input a,b,c\n"); scanf...

    学习C语言数据类型和运算符及表达式复习题.pdf

    15. **表达式求值**:表达式如a*b/c/d、a/(c*d)*b、a*b/(c*d)分别代表不同的代数式,需要注意类型转换和运算顺序。 16. **类型转换和表达式求值**:表达式t=1,t++,t+5中,t首先被赋值为1,然后自增变为2,最后加上5...

    智慧职教C语言趣味编程单元测试及考试答案.pdf

    选项A、B和C都不合法,而D`SHORTINT`是一个合法的变量名,因为它是以字母开头,且不是C语言的保留关键字。 8. `switch`语句:`switch`语句中的`case`后面可以跟常量或常量表达式,不一定是变量。因此,正确答案是B...

    c语言程序设计与项目实践课程.ppt

    例如,范例 3.1(PriorityAndCombine.c)展示了如何通过赋值运算符`+=`来组合多个运算符,演示了运算顺序和结果。 赋值运算符如`=`用于将右侧的值赋予左侧的变量,而复合赋值运算符如`+=`,`-=`等则简化了对变量的...

    calculate.rar_java表达式运算

    Java 支持包括括号在内的复杂数学表达式,通过运算符的优先级和结合性来确定运算顺序。例如,`num1 + (num2 * num3) / num4` 会先进行括号内的乘法,然后是除法,最后是加法。 3. **Scanner类**: 通常,我们使用...

    C语言程序设计习题集第2章(答案)基本数据类型及顺序结构程序设计[归类].pdf

    `print`、`DATE`和`_2007`是合法的,而`&a`、`y-m-d`和`Dr.Tom Big1`不是。 3. 字符常量:字符常量是由单引号包围的单个字符,如 `'C'`。`'\xCC0'`是十六进制的字符常量,`'\072'`是八进制的字符常量。双引号包围的...

    C语言试题及答案.doc

    例如,在`(m=a>b)&&(n=c>d)`这个表达式中,`a>b`和`c>d`都会先进行比较,然后根据比较结果决定是否进行赋值操作,最后得出`m`和`n`的值。 总的来说,C语言试题涵盖了语言的基本概念、语法、数据类型、运算符和...

    ch03密码验证程序同步训练第一讲.pdf

    在C语言中,编程涉及了各种运算符和逻辑表达式,这些都是编写程序的关键元素。本节将详细讨论从题目中提取的几个知识点。 1. **关系表达式**:关系表达式的结果是布尔值(`bool`类型),在C语言中以`1`表示“真”...

    C语言高职复习试题库-填空题.doc

    a||b+c&&b==c`的值取决于`a`、`b+c`和`b==c`的布尔值组合。 - `a=17.0/3*3`的结果是17,因为浮点数除法后乘以整数会向下取整。 - `a>b>c`的值是`0`,因为`b`不小于`c`。 - 执行`--a || --b && ++c;`后,`b`和`c`...

    1.3 编程基础之算术表达式与顺序执行 python版.rar

    "09 与圆相关的计算.py"很可能是关于圆的几何计算,如计算半径、直径、周长(C=2πr)和面积(A=πr^2)。 "14 大象喝水.py"可能是一个有趣的实例,用以解释如何通过乘法计算大象的饮水量,比如大象每天需要喝多少...

Global site tag (gtag.js) - Google Analytics