2.5 表达式和运算符
21天学通Java(第6版)
表达式是一条能够提供值的语句。最常见的是数学表达式,如下面的例子所示:
这3条语句都是表达式—它们提供了可被赋给变量的值。第1条语句将字面量3赋给变量x。第2条语句将变量x的值赋给变量y。在第3条语句中,乘法运算符*用来将x和y相乘,结果存储在变量z中。
表达式可以是任何变量、字面量和运算符的组合,也可以是方法调用,因为方法能够将一个值返回给调用它的类或对象。
您知道,表达式所提供的值称为返回值。在Java程序中,可将这个值赋给变量或以其他方式使用。
大多数Java中的表达式使用了运算符,如*。运算符是一些特殊符号,用于数学函数、赋值语句和逻辑比较。
2.5.1 算术运算符
在Java中,有5种用来完成基本算术运算的运算符,如表2.3所示。
每个运算符都有两个操作数,一边一个。减法运算符也可以用来对单个操作数求反,即将操作数与−1相乘。
使用除法时,要注意操作数的类型。如果将除法运算的结果存储在整型变量中,结果将向下取整,因为int类型不能处理浮点数。
例如,如果将结果存储在int变量中,则表达式31/9的结果为3。
使用运算符%的求模运算得到的是除法运算的余数。例如,31%9的结果是4,因为31被9除的余数是4。
很多针对整数的算术运算的结果为int值,而不管操作数是什么类型。处理其他数值类型,如浮点数或长整型时,应确保操作数的类型与所需结果的类型相同。
要创建的下一个项目是个Java类,它演示了Java的简单算术运算。为此,在NetBeans中新建一个名为Weather的空Java文件,并在源代码编辑器中输入程序清单2.2所示的代码。输入完毕后将该文件存盘。
程序清单2.2 源代码文件Weather.java
选择菜单“运行”>“运行文件”运行该程序,它将在NetBeans“输出”窗口中生成如下输出:
输出:
该Java应用程序的第3~12行使用算数运算符将华氏温度转换为摄氏温度。
- 第3行:声明浮点变量fah,并将其初始化为86。
- 第4行:显示fah的当前值。
- 第5行:第一个注释,解释了该程序的功能。这些注释将被Java编译器忽略。
- 第7行:将fah的值减去32。
- 第9行:将fah的值除以9。
- 第11行:将fah的值乘以5。
- 第12行:将fah的值转换为摄氏温度后,再次显示它。
- 第14~23行与此类似,但执行相反的转换—将摄氏温度转换为华氏温度。
2.5.2 再谈赋值
给变量赋值的语句是一个表达式,因为它生成一个值。因此,可以像下面这样将赋值语句连在一起:
在这条语句中,所有3个变量(x、y和z)的值最后都为7。
在赋值之前,将首先计算赋值表达式右边。因此,可以这样使用表达式语句:
在表达式x = x + 2中,首先计算x+2;然后将结果(7)赋给变量x。
在编程中,使用表达式来修改变量的值是一项常见的任务。有几个专门用于这方面的运算符。
表2.4列出了这些赋值运算符及等效的表达式。
警告这些简化的赋值运算符与它们所代表的更长的赋值语句等效。然而,如果赋值语句的一边是复杂的表达式,将出现不再等效的情况。例如,如果x等于20,y等于5,下面两条语句的结果将不同:
有疑问时,应使用多条赋值语句来简化表达式,而不要使用简化的运算符。
2.5.3 递增和递减运算符
另一种常见的编程任务将整型变量加1或减1。有专门用于完成这种运算的运算符:递增和递减运算符。对变量做递增运算意味着将它的值加1,做递减运算意味着将它的值减1。
递增运算符是++,递减运算符是−−。这些运算符位于变量名的前面或后面,如下所示:
其中语句x = x++将变量x的值从7增加到8。
递增和递减运算符可放在变量名的前面或后面,这将影响表达式的结果。
如果递增和递减运算符位于变量名前面,则被称为前缀运算符;如果位于变量名后面,则被称为后缀运算符。
在简单表达式(如counts--;)中,无论使用前缀还是后缀运算符,结果都相同,因此它们可以互换。然而,当递增和递减运算符被用于更复杂的表达式中时,选择前缀还是后缀运算符就至关重要。
请看下面的代码:
上述3个表达式由于前缀和后缀运算符的差别而产生完全不同的结果。
使用后缀运算符时,先使用变量的值,再将变量递增或递减。因此,在y = x++中,先将x的值赋给y,再将x的值加1。
使用前缀运算符时,先将变量递增或递减,再使用变量的值。例如,在z = ++x中,先将x的值加1,再将x的值赋给z。
上述代码的最终结果是,y等于42,z等于44,x等于44。
如果对此还不清楚,下面的例子再次通过注释描述了每一步的情况:
警告在特别复杂的表达式中使用递增和递减运算符时,很可能得到意外的结果。“将x自增之前将x的值赋给y”这一概念不再完全正确,因为Java总是先计算表达式右边的内容,然后再把结果赋给表达式左边的变量。Java在处理表达式之前会存储一些值,以便后缀运算符能够像本节介绍的那样工作。当包含前缀和后缀运算符的复杂表达式的结果不同于您的期望时,请将该表达式拆成多个语句,以简化它。
2.5.4 比较运算符
Java有几种可用于对变量之间、变量和字面量(或其他类型的信息)之间进行比较的运算符。
这些运算符用于返回布尔值(true或false)的表达式,表达式的返回值取决于比较的结果是真还是假。表2.5列出了这些比较运算符。
表达式age<25的结果为true还是false取决于age的值。由于这里的age为45(比25大),因此isHip为布尔值false。
2.5.5 逻辑运算符
结果为布尔值的表达式(如比较运算)可以被组合成更加复杂的表达式。这是通过逻辑运算符来实现的,逻辑运算符用于逻辑组合:AND、OR、XOR和逻辑NOT。
对于AND组合,可使用逻辑运算符&或&&。当两个布尔表达式通过&或&&组合在一起后,仅当两个布尔表达式都为真时,整个表达式的结果才为true。
请看下面的例子:
这个表达式将两个比较表达式(score > 75000和playerLives <10)组合在一起。如果这两个表达式都为真,则true被赋给变量extraLife;在其他情况下,false被赋给extraLife。
&和&&之间的差别在于Java对组合表达式所做的工作量。如果使用&,则不管什么情况下,&两边的表达式都将被计算;如果使用&&,则当左边的表达式为false时,将不计算右边的表达式。
对于OR组合,可使用逻辑运算符|或||。如果运算符两边的任何一个布尔表达式为真,则组合表达式的结果为true。
请看下述示例:
该表达式合并了两个比较表达式:score > 75000和playerLevel == 0。如果这两个表达式中的任何一个为真,则true被赋给变量extraLife;仅当这两个表达式都是false时,false才被赋给extraLife。
注意,这里使用的是||,而不是|。因此,如果score > 75000为true,则extraLife将被设置成true,而第二个表达式不会被计算。
用于XOR合并的逻辑运算符只有一个:^。仅当被合并的两个布尔表达式的值相反时,整个表达式的结果才为true;如果两个表达式都是true或都是false,则^运算符的结果为false。
NOT组合使用逻辑运算符!,后面跟一个表达式。它对布尔表达式的值求反,这与用负号来改变数字的符号相同。例如,如果age<30的结果为true,则!(age<30)的结果将为false。
首次见到这些逻辑运算符时,可能觉得它们完全不符合逻辑。在本周余下的课程中,您将大量地使用它们,尤其是在第5章。
2.5.6 运算符优先级
当表达式中有多个运算符时,Java有一套优先级用来判断运算符的执行顺序。在许多情况下,优先级决定了整个表达式的最终值。
例如,请看下面的表达式:
变量y的值为5还是8取决于哪个算术运算先被处理。如果先计算表达式6+4,则y的值为5;否则为8。
通常,从先到后的顺序如下:
1.递增和递减运算;
2.算术运算;
3.比较运算;
4.逻辑运算;
5.赋值运算。
如果两个运算的优先级相同,则左边的比右边的先被处理。表2.6列出了Java中众多运算符的优先级。排在越前面的运算符的优先级越高。
表2.6 运算符优先级
表2.6中的多个运算符都将在本周后面的课程中介绍。
回过头来看表达式y =6 + 4 / 2。表2.6表明,除法先于加法计算,因此y的值为8。
要改变表达式求值的顺序,可以用圆括号将需要先计算的表达式括起。可以嵌套圆括号以确保按所需的顺序对表达式进行求值—最里边的圆括号内的表达式最先被计算。
下述表达式的结果为5:
因为先计算6 + 4,得到10,然后再除以2,最后的结果为5。
圆括号还可以提高表达式的可读性。如果不能一眼看出表达式的优先级,可以添加圆括号来强制转换为希望的优先级,使语句更容易理解。