Java是面向表达式的语言,Java中一个简单表达式可以是下面任意一种:
● 常量:7、false。
● 单引号括起来的字符字面常量:'A'、'3'。
● 双引号括起来的字符串字面常量:"foo"、"Java"。
● 任何正确声明的变量名:myString、x。
● 任何用Java二元运算符(本章稍后将详细讨论)连接起来的两个上述类型的表达式:x+2。
● 任何用Java一元运算符(本章稍后将详细讨论)修饰的单个上述类型的表达式:i++。
● 任何用小括号括起来的上述类型的表达式:(x+2)。
以及另外一些与本书后面将要学到的对象有关的表达式类型。
无论多么复杂的表达式都可以由不同类型的简单表达式和括号嵌套组合而成,例如:((((4/x) + y) * 7) + z)。
一、 算术运算符
Java语言提供了许多基本的算术运算符,如表2-1所示。
表2-1 Java算术运算符
运算符 | 描述 |
+ | 加法 |
- | 减法 |
* | 乘法 |
/ | 除法 |
% | 取余数 10%3=1 |
+和-运算符也可作为一元运算符用于表示正负数:-3.7、+42。
除了简单赋值运算符=,还有许多特定的复合赋值运算符,这些运算符将变量赋值和算术操作合并在一起,如表2-2所示。
表2-2 Java复合赋值运算符
运算符 | 描 述 |
+= | a+=b等价于a=a+b |
-= | a-=b等价于a=a-b |
*= | a*=b等价于a=a*b |
/= | a/=b等价于a=a/b |
%= | a%=b等价于a=a%b |
最后要介绍的两个算术运算符是一元递增运算符(++)和一元递减运算符(--),用于将整数变量的值加1或减1,或者将浮点数变量的值加1.0或减1.0。称它们为一元运算符是因为它们用于单个变量,而前面讨论的二元运算符则连接两个表达式的值。
一元递增运算符和一元递减运算符也可用于将字符变量在Unicode序列中向前或向后移动一个字符位置。例如,在下面的代码片段中,字符变量c的值从'e'递增为'f':
char c='e';
c++; //自加后,c='f'
递增和递减运算符可以以前缀或者后缀方式使用。如果运算符放在操作数之前(前缀模式),变量的递增或递减操作将在更新后的变量值被用于任何由它构成的赋值操作之前执行。例如,考虑下面的使用前缀递增运算符的代码片段,假设a和b在程序前面已经声明为int变量:
a=1;
b=++a;
上述代码执行后,变量a的值是2,变量b的值也是2。这是因为在第二行中变量a的递增(从1到2)发生在它的值赋给b之前。因此这行代码
b=++a;
在逻辑上等价于下面两行代码:
a=a+1;
b=a;
另一方面,如果运算符放在操作数之后(后缀模式),递增或递减操作发生在原来的变量值被用于任何由它构成的赋值操作之后。看一下以后缀方式使用递增运算符的相同代码片段:
a=1;
b=a++;
上述代码执行后,变量b的值是1,而变量a的值是2。这是因为在第二行中变量a的递增(从1到2)发生在它的值赋给b之后。因此这行代码
b=a++;
在逻辑上等价于下面两行代码:
b=a;
a=a+1;
下面是一个稍微复杂一点例子,请阅读附加的注释以确保你能够明白x最终是如何被赋值为10的:
int y=2;
int z=4;
int x=y++ * ++z;
上面语句中,先进行自加自减运算,++ 在变量后面,先运算后自加,y++值仍然为2 , ++在变量前面,先自加后运算,++z值为5,所以乘积为10.
稍后将会看到,递增和递减运算符通常和循环一起使用。
二、 关系和逻辑运算符
逻辑表达式以指定的方式比较两个(简单或者复杂)表达式exp1和exp2,决议出一个boolean值true或者false。
Java提供了表2-3所示的关系运算符来创建逻辑表达式。
Java关系运算符
运算符 | 含义 |
== | 等于 |
!= | 不等于 |
> | 大于 |
< | 小于 |
>= | 大于等于 |
<= | 小于等于 |
Java逻辑运算符
运算符 | 名称 |
& | 与 |
| | 或 |
^ | 异或 |
&& | 短路与 |
|| | 短路或 |
! | 逻辑非 |
符号
|
名称
|
功能说明
|
&&
|
逻辑与
|
两个条件同时为true整个表达式才为true,否则为false
|
||
|
逻辑或
|
两个条件有一个为true则整个表达式为true,否则为false
|
!
|
逻辑非
|
对原表达式值取反
|
下面这个例子用逻辑“与”运算符来编程实现逻辑表达式“如果x大于2.0且y不等于4.0”:
if((x>2.0)&&(y!=4.0)){……}
逻辑表达式常用于流程控制结构,稍后将进行讨论。
三、 表达式求值和运算符优先级
如同本章前面提到的那样,任何复杂的表达式都可以用分层嵌套的小括号构成,例如(((8 * (y + z)) + y) x)。编译器通常按照从内到外,从左到右的顺序对这样的表达式求值。假设x、y、z按照下面的方式声明并初始化:
int x=1;
int y=2;
int z=3;
下面的赋值语句右边的表达式:
int answer=((8*(y+z))+y)*x;
将像下面这样逐步求值:
没有小括号时,根据运算符用于表达式求值的顺序,某些运算符具有高于其他运算符的优先级。例如,乘除法先于加减法执行。通过使用小括号可以强制改变运算符的优先级,括号内的运算符比括号外的先执行。考虑下面的代码片段:
int j=2+3*4;
int k= (2+3)*4;
代码的第一行没有使用括号,乘法操作比加法操作先执行,因此整个表达式的值为2+12=14,就像我们将表达式明确地写成2+(3*4)一样,当然这样做没有必要。
在代码的第二行,括号被明确地放在操作2+3两边,因此加法操作将首先执行,然后求和结果乘以4作为整个表达式的值,即5*4=20。
回到前面的例子
if((x>2.0)&&(y!=4.0)){……}
注意到>和!=运算符优先级高于&&运算符,因此可以去掉嵌套的括号而变成下面这样:
if(x>2.0 && y!=4.0){……}
然而,额外的括号并不会对代码造成伤害,事实上它可以使表达式的目的更加清楚。
2.9.4 表达式类型
表达式类型是表达式最终求值结果的Java类型。例如给定下面的代码片段:
double x=3.0;
double y=2.0;
if((x>2.0)&&(y!=4.0)){……}
表达式(x > 2.0) && (y != 4.0)求值结果为true,因此表达式(x > 2.0) && (y != 4.0)称为boolean型表达式。在下面的代码片段中:
int x=1;
int y=2;
int z=3;
int answer=((8*(y+z))+y)*x;
表达式((8 * (y + z)) + y) * x求值结果为42,因此表达式((8 * (y + z)) + y) * x称为整型表达式。