2.2 运算符和表达式
在Java中,运算符和表达式是实现数据操作的两个重要的组成部分。运算符是指表达各种运算的符号。表达式是符合一定语法规则的运算符和操作数的序列。
2.2.1 运算符
Java中表达各种运算的符号称为运算符,运算符的运算对象称为操作数。只需要一个操作数参与运算的运算符称为单目运算符,如+(正号)、-(负号)等。需要两个操作数参与运算的运算符称为双目运算符,如×(乘)、+(加)等。需要三个操作数参与运算的运算符称为三目运算符,如?:(条件运算符)。
表2-3列出了Java中的运算符及其相关的内容。
表2.3 Java 运算符一览表
1.算术运算符
算术运算符用于处理整型、浮点型、字符型的数据,进行算术运算。
Java对“+”做了重载(Java中唯一重载的符号),如"abc" + var_a,其中变量“var_a”可为任何Java类型。如"abc" + 12.6 结果是:"abc12.6"。又如12.6 + "abc",结果是:"12.6abc"。再如int a = 10,b = 11,则"a + b = " + a + b值是"a + b = 1011"。而"a + b = " + (a +b)值是"a + b = 21"。
“/”用于整型表示取整,如7/2 结果为3。“/”用于float、double表示实数相除,如7.0/2 结果为3.5。例如下面的语句:
int a = 7,b = 2; float c; c = a / b;
c的值仍是3.0f。因此若要使a/b按实数除法进行,可用强制类型转换:c = (float)a/b;即先将a的类型转换成float类型,然后“/”将按实数相除进行。
“%”用于整型表示取余数。如15%2结果为1、(-15) % 2结果为-1、15 % (-2) 结果为1、(-15) % (-2) 结果为-1。“%”用于float、double表示实数取余,如15.2%5 = 0.2。
“++”表示自增,有前自增如++a与后自增a++两种,其中a必须是一个变量。++a表示:先将a的值增加1,然后a的值(已增加1)即为整个表达式(++a)的值。a++表示:先将a的值(未增加)作为整个表达式(a++)的值。然后a的值增加1。
“--”表示自减,有前自减如--a与后自减a--两种,其中a必须是一个变量。--a表示:先将a的值减少1,然后a的值(已减少1)即为整个表达式(--a)的值。a--表示:先将a的值(未减少)作为整个表达式(a--)的值。然后a的值减少1。
在Java中没有乘幂运算符。若要进行乘幂运算,如xy,则可用类Math的pow()方法:Math.pow(x,y)。
【例2.2】 测试自增和自减运算符的作用。
public class Test { public static void main(String[] args) { int i1 = 5, i2 =10; int i = (i2++); System.out.println("i="+i); System.out.println("i2="+i2); i=(++i2); System.out.println("i="+i); System.out.println("i2="+i2); i=(--i1); System.out.println("i="+i); System.out.println("i1="+i1); i =(i1--); System.out.println("i="+i); System.out.println("i1="+i1); } }
程序运行结果:
i=10 i2=11 i=12 i2=12 i=4 i1=4 i=4
Test.java
i1=3
2.关系运算符
关系运算符用于比较两个操作数,运算结果是布尔类型的值true或false。所有关系运算符都是二目运算符。Java中共有六种关系运算符:>(大于)、>=(大于等于)、<(小于)、<=(小于等于)、!=(不等于)、= =(等于)。前四种优先级相同,且高于后面的两种。如a= = b> c等效于a = = (b > c)。在Java中,任何类型的数据(无论是基本数据类型还是引用类型)都可以通过==或!=来比较是否相等或不等。如布尔类型值true= =false运算结果是:false。只有char、byte、short、int、long、float、double类型才能用于前四种关系运算,这些运算符的优先级与结合方向如表2-3所示。
表2-3 Java运算符一览表
3.逻辑运算符
布尔逻辑运算符用于将多个关系表达式或true 、false组成一个逻辑表达式。Java中的逻辑运算符:&(与)、|(或)、!(非)、^(异或)、&&(短路与)、‖(短路或)。
a && b:只有a与b都为true,结果才为true;有一个为false,结果为false。
a || b:只有a与b都为false,结果才为false;有一个为true,结果为true。
! a:与a的值相反。
Java中逻辑表达式进行所谓的“短路”计算。如计算a || b && c时,若a的值为true,则右边b && c就不需进行计算,最后结果一定是true。只有当a为false时,右边b && c才有执行的机会。当进一步计算b && c时,仍是短路计算。当b是false时,c不用计算。只有当b为true时,c才有执行的机会。Java编译程序按短路计算方式来生成目标代码。
这三个运算符的优先级与结合方向如表2-3所示。
【例2.3】 测试逻辑运算符的作用。
LogicTest.java
public class LogicTest { public static void main(String[] args) { boolean a,b,c; a = true; b = false; c = a & b; System.out.println(c); c = a | b; System.out.println(c); c = a ^ b; System.out.println(c); c =!a; System.out.println(c); c = a && b; System.out.println(c); c = a ||b; System.out.println(c); } }
程序运行结果:
false true true false false true
4.位运算符
位运算符是对操作数按其在计算机内部的二进制表示按位进行操作。参与运算的操作数只能是int、long类型,其他类型的数据要参与位运算要转换成这两种类型。Java中共有七种位运算符:
~(按位求反)、&(与)、|(或)、^(异或)、>>(保留符号的右移)、>>>(不保留符号的右移)、<<(左移)。
● 按位求反运算符~
~是单目运算符,对操作数的二进制数据的每一个二进制位都取反,即1 变成0,而0变成1。例如,~10010011 结果是01101100。
● 与运算符&
参与运算的两个操作数,相应的二进制数位进行与运算。即0 & 0 = 0,0 & 1 = 0,1 & 0 = 0,1 & 1 = 1。即x & 0 = 0,x & 1 = x。其中:x是0或1。例如,a = 11001011,则a = a &11111100 的结果是a的值变为11001000,即将数a的前六位不变,最后两位清零。保持不变的位,要用1 去进行&运算,而要清零的位,要用0 去进行“&”运算。例如,a = 11001010,b = a & 00000011,则b的值是00000010,即取出变量a中的最后两位二进制位。
● 或运算符|
参与运算的两个操作数,相应的二进制数位进行或运算。即0 | 0 = 0,0 | 1 = 1,1 | 0 =1,1 | 1 = 1。即| 0 = x,x | 1 = 1,其中:x是0或1。例如,a = 11001000,则a = a |00000011的结果是a的值变为11001011,即将数a的前六位不变,最后两位置1。保持不变的位,要用0去进行“|”运算,而要置1的位,要用1去进行“|”运算。
● 异或运算符^
参与运算的两个操作数,相应的二进制数位进行异或运算。即0^0=0,1^0=1,0^1=1,1^1=0。即不相同是1,相同是0。例如,a=10100011,则a = a ^ 10100011 的结果是00000000。
● 保留符号位的右移运算符>>
将一个操作数的各个二进制位全部向右移若干位,左边空出的位全部用最高位的符号位来填充。例如,a = 10100011,则a = a>>2的结果是a的值为11101000。
向右移一位相当于整除2,用右移实现除法运算速度要比通常的除法运算速度要快。
设a是32位的int类型变量,如a = 0x7fffffff;,则b = a >> 31的结果是b的值,为0x00000000。但b = a >> 34的结果是b的值并不是0x00000000,与b = a >> 2相同。即Java对32位整型数的右移,自动先对所要移动的位的个数进行除以32取余数的运算,然后再进行右移。即若a是int型变量,则a >> n就是a >> ( n %32)。同样,若a是64位的长整数类型,Java自动先对移动的位的个数进行除以64 取余数的运算,然后再进行移位,即a >> n就是a>> ( n%64 )。例如,a = 0xffffffff77777777L,则b = a>>66与b = a >> 2相同。另外,a>>(-2)等价于a>>(-2+32),即a>>30。
● 不保留符号位的右移运算符>>>
与>>不同的是,右移后左边空出的位用0 填充。同样在移位之前,自动先对所要移动的位的个数进行除以32(或64)取余数的运算,然后再进行右移。即若a是int型,则a>>> n就是a >>> ( n%32 ),若a是long型,则a >>> n就是a >>> ( n % 64 )。
● 左移运算符<<
将一个操作数的所有二进制位向左移若干位,右边空出的位填0。同样,在移位之前,自动先对所要移动的位的个数进行除以32(或64)取余数的运算,然后再进行左移。即若a是int型,则a< < n就是a << ( n%32 ),若a是long型,则a << n就是a << ( n % 64 )。
在不产生溢出的情况下,左移一位相当于乘以2,用左移实现乘法运算的速度比通常的乘法运算速度要快。
5.赋值运算符
● 赋值运算符=
在Java中,赋值运算符=是一个双目运算符,结合方向从右向左。用于将赋值符右边的操作数的值赋给左边的变量,且这个值是整个赋值运算表达式的值。若赋值运算符两边的类型不一致,且右边操作数类型不能自动转换到左边操作数的类型时,则需要进行强制类型转换。例如下面的语句:
float f = 2.6f; int i=f; //出错,因为float不能自动转换成int
故应改为:
int i=(int)f; //强制类型转换,此时i的值是2
● 复合赋值运算符
在Java中规定了11种复合赋值运算符,如表2-4所示。
表2-4 复合赋值运算符
各种赋值运算符的优先级均相同且是右结合的。赋值运算符的优先级最低,如表2-3所示。例如,int x = 1; x += 2.0f; 等价于:x = (int)(x+2.0f)。
6.条件位运算符
条件运算符?:是三目运算符,其格式是:
e1?e2:e3
其中e1是一个布尔表达式,若e1的值是true,则计算表达式e2的值,且该值即为整个条件运算表达式的值,否则计算表达式e3的值,且该值即为整个条件运算表达式的值。e2与e3需要返回相同的或兼容的数据类型,且该类型不能是void。例如,int a=4,b=8;minValue= a>b? b:a ;。
2.2.2 表达式
表达式是符合一定语法规则的运算符和操作数的序列。一个常量、变量也认为是一个表达式,该常量或变量的值即为整个表达式的值。一个合法的Java表达式经过计算后,应该有一个确定的值和类型。唯一的例外是方法调用时,该方法的返回值类型被定义为void。通常,不同的运算符构成不同的表达式。例如,关系运算符>、>=等构成关系表达式,关系表达式的值只能取true或false,其类型为boolean型。