Java语言程序设计教程
上QQ阅读APP看书,第一时间看更新

2.2 操作符和表达式

在Java语言中,可以对程序中的数据进行操作运算,参与运算的数据称为操作数(Operand),对操作数运算时所使用的各种运算的符号称为操作符(Operator)。

Java语言操作符的作用是指明用户对操作数进行的某种操作,由Java编译器负责解释执行。按照操作符处理操作数的个数,将操作符分为单目操作符、双目操作符和三目操作符等。按照操作符处理数据的功能,将操作符分为算术操作符、关系操作符、逻辑操作符、位操作符、赋值操作符、条件操作符和其他操作符等。

由操作符运算数据时形成的组合写法称为相应的表达式(Expression)。Java语言表达式一般是由Java语言操作符和括号将Java语言操作数(如变量或常量)连接起来得到一个确定值的式子,它始终贯穿在程序设计过程中。与操作符的分类对应,Java语言表达式可分为算术表达式、关系表达式、逻辑表达式、位表达式、赋值表达式、条件表达式和其他表达式等。

2.2.1 算术操作符和算术表达式

算术操作符是指对各种整数或浮点数等数值进行运算操作的符号,用于算术运算。由算术操作符和操作数连接组成的表达式称为算术表达式。算术操作符和算术表达式如表2-5所示。

表2-5 算术操作符和算术表达式

例题2.2 封装了Java语言算术操作符和算术表达式运算的程序。

2.2.2 关系操作符和关系表达式

关系操作符是用来比较两个操作数之间的关系大小或相等的运算符。由关系操作符和操作数连接组成的表达式称为关系表达式。关系表达式的操作结果是布尔类型(boolean),如果操作符运算操作数对应的关系成立,关系表达式的结果为true,否则为false。关系操作符和关系表达式如表2-6所示。

表2-6 关系操作符和关系表达式

2.2.3 逻辑操作符和逻辑表达式

逻辑操作符是用来对布尔类型的逻辑值进行运算的操作符,它也可以连接关系表达式。由逻辑操作符和布尔逻辑值或关系表达式连接组成的表达式称为逻辑表达式。逻辑表达式的操作结果是布尔类型(boolean),如果操作符运算操作数对应的关系成立,关系表达式的结果为true,否则为false。逻辑操作符和逻辑表达式如表2-7所示。

表2-7 逻辑操作符和逻辑表达式

逻辑操作符&和&&、|和||计算的结果是相同的,但反映在计算过程中有所区别。在计算含有逻辑与(&)和逻辑或(|)的逻辑表达式的值时,程序要先计算操作符两端的操作数,再进行逻辑运算。而在计算含有短路与(&&)和短路或(||)的逻辑表达式的值时,如果操作符前面的子表达式的值已经确定整个表达式的值,则操作符后面的表达式不再进行计算。例如:(op1>op2)&&(op3<++op4),如果已知op1>op2的值为false,则不用再去计算后面表达式的值,直接得到整个表达式的值为false。

例题2.3 描述了逻辑操作符和逻辑表达式的应用。定义某一年的变量为year,写出判断某一年是否是闰年的表达式。

判断year是否是闰年的条件有两种:一种是year能被4整除,但不能被100整除;另一种是能被4整除,同时又能被400整除。

用逻辑表达式表示为:(year%4==0&&year%100!=0)||year%400==0,当year为一个整数值时,如果表达式的值为true,则这一年year为闰年,否则为非闰年。

用逻辑表达式表示为:(year%4!=0)||(year%100!=0&&year%400!=0),当year为一个整数值时,如果表达式的值为true,则这一年year为非闰年,否则为闰年。

2.2.4 位操作符和位操作表达式

位操作符是用来对整数型数据(byte、short、char、int和long)的每一位二进制数进行运算的操作符。由位操作符和二进制的操作数连接组成的表达式称为位操作表达式。虽然位操作符和算术操作符都可以对数值运算,但算术操作符并不关心数值在计算机内部的表示方式,而位操作符则需要处理数值的每一位二进制数。由于Java语言的位操作符接近于计算机底层的数据控制,所以Java语言经常用于一些嵌入式设备(如数字电视机顶盒)的程序设计等。位操作符和位操作表达式如表2-8所示。

表2-8 位操作符和位操作表达式

续表

1.位取反操作(~)

位取反操作符是单目操作符,它对操作数的每个二进制位按位取反,即把1变为0,把0变为1。例如:~10110011的结果为01001100。

2.位与操作(&)

位与操作符是双目操作符,它对两个操作数的相应二进制位进行与运算,与运算规则为:

0&0=0,0&1=0,1&0=0,1&1=1。

例如:10110011&00101111的结果为00100011。

位与操作可以用来屏蔽特定的位,即对特定的位清零。例如:设一个int类型的变量aint,其值为17,存在表达式aint&8,则表示对变量aint的最右边8位二进制数(00010001)与8的最右边8位二进制数(00001000)进行按位与运算,表达式的结果为0(00000000)。此表达式的运算结果说明经过表达式aint&8的运算,变量aint的二进制数据中,除了右数第4位没有变化外,其余位均被清零,即被屏蔽掉了。

位与操作还可以用来取出一个数据中某些指定的位。例如:设一个int类型的变量aint,其值为17,存在表达式aint&24,则表示对变量aint的最右边8位二进制数(00010001)与24的最右边8位二进制数(00011000)进行按位与运算,表达式的结果为16(00010000)。此表达式的运算结果说明经过表达式aint&24的运算,将变量aint的二进制数据中右数第4位和右数第5位不加改变的得到了,其他位则被屏蔽掉了。

3.位或操作(|)

位或操作符是双目操作符,它对两个操作数的相应二进制位进行或运算,或运算规则为:

0|0=0,0|1=1,1|0=1,1|1=1。

例如:10110011|00101111的结果为10111111。

位或操作可以用来将一个数据中的某些特定的位设置为1。例如:设一个int类型的变量aint,其值为17,存在表达式aint|24,则表示对变量aint的最右边8位二进制数(00010001)与24的最右边8位二进制数(00011000)进行按位或运算,表达式的结果为25(00011001)。此表达式的运算结果说明经过表达式aint|24的运算,变量aint的二进制数据中,除了右数第4位和右数第5位被设置为1外,其余位均没有变化。

4.位异或操作(^)

位异或操作是双目操作符,它对两个操作数的相应二进制位进行异或运算,异或运算规则为:

0^0=0,0^1=1,1^0=1,1^1=0。

例如:10110011^00101111的结果为10011100。

位异或操作可以将一个数据中的某些特定的位翻转,即取反,可使用另一个相应位为1的操作数与原来的数据进行按位异或操作来实现。例如:设一个int类型的变量aint,其值为17,存在表达式aint^8,则表示对变量aint的最右边8位二进制数(00010001)与8的二进制数最右边8位(00001000)进行按位异或运算,表达式的结果为25(00011001)。此表达式的运算结果说明经过表达式aint^8的运算,变量aint的二进制数据中,除了右数第4位被设置为1外(由0翻转为1),其余位均没有变化。

位异或操作还可以实现两个数值的互换,而不使用临时变量。例如:设两个int类型的变量aint=17和bint=30,表示变量aint的最右边8位二进制数为(00010001),变量bint的最右边8位二进制数为(00011110),存在操作aint=aint^bint,即aint=00010001^00011110,此时aint的值变为15(00001111),接着操作bint=bint^aint,即bint=00011110^00001111,此时bint的值变为17(00010001),最后操作aint=aint^bint,即aint=00001111^00010001,此时aint的值变为30(00011110),实现了在不使用临时变量的情况下,aint和bint值的互换。

无论哪种位运算操作,当两个操作数的数据长度不同时,例如:存在表达式aint|bint,aint为long类型,bint为int类型(或char类型),编译器会自动将bint的左侧32位(或48位)补齐。如果bint为正数,则左侧补齐0,如果bint为负数,则左侧补齐1。此时,位操作表达式将得到两个操作数中数据长度较大的数据类型。

5.带符号位右移操作(>>)

计算机中表示二进制数时总是要区分正负数的,Java语言使用补码表示带符号的二进制数。在补码表示中,最高位为符号位,其余各位表示相应的二进制数值本身。正数的符号位为0,负数的符号位为1。如果对char、byte或short类型的数值进行移位操作,在进行移位之前,Java编译器会将其转换为int类型,并且只对数值右端的低5位才有效,以防止移位超过int类型值所具有的位数,得到的结果也是一个int类型的值。如果对long类型的数值进行移位操作,Java编译器只对数值右端的低6位有效,以防止移位超过long类型值所具有的位数,得到的结果也是一个long类型的值。

带符号位右移操作符是双目操作符,它用来将一个数的二进制位右移若干位,移到右端的低位被舍弃,最高位则移入原来高位的值(称为符号扩展)。例如:设一个int类型的变量aint,其值为+17(00010001),存在表达式aint>>2,表示将aint的二进制位右移2位,此时表达式的结果为+4(00000100)。再如:设一个int数类型的变量bint,其值为-17(10010001),存在表达式bint>>2,按照上述规则,此时表达式的结果为-4(11100100)。

对于整数类型的数值进行带符号右移操作时,右移一位相当于除以2取商,余数舍弃。在计算机中需要进行2的倍数除法时,带符号右移实现比除法速度要快得多。

6.带符号位左移操作符(<<)

带符号位左移操作符是双目操作符,它用来将一个数的二进制位左移若干位。例如:设一个int类型的变量aint,其值为+17(00010001),存在表达式aint<<2,表示将aint的二进制位左移2位,移动时最高位移出,最低位补0,此时表达式的结果为+68(01000100)。再如:设一个int数类型的变量bint,其值为-17(10010001),存在表达式bint<<2,按照上述规则,此时表达式的结果为-68(01000100)。

对于整数类型的数值进行带符号左移操作时,在不产生溢出的情况下,左移一位相当于乘以2。在计算机中需要进行2的倍数乘法时,带符号左移实现比乘法速度要快得多。

7.无符号位右移操作符(>>>)

无符号位右移操作符是双目操作符,它用来将一个数的二进制位右移若干位,移到右端的低位被舍弃,最高位均以0补齐。例如:设一个int类型的变量aint,其值为17(00010001),存在表达式aint>>>2,表示将aint的二进制位无符号右移2位,此时表达式的结果为68(01000100)。

对于整数类型的数值进行无符号右移操作时,不考虑符号的影响,在进行图形程序操作时经常用到。

例题2.4 封装了位操作符和位操作表达式的程序。

2.2.5 赋值操作符和赋值表达式

赋值操作符(=)是把一个确定的值传递给一个变量的操作符,由赋值操作符、变量和值连接起来的表达式称为赋值表达式,通常在赋值操作符的左侧是一个变量,右侧是一个表达式或值。一般要求赋值操作符两端的数据类型要一致,当赋值操作符两端的数据类型出现不一致的情况时,如果可以实现自动类型转换或强制类型转换,Java编译器不会报错;如果不能实现自动类型转换或强制类型转换,Java编译器将报出语法错误。赋值操作符和赋值表达式如表2-9所示。

表2-9 赋值操作符和赋值表达式

续表

2.2.6 条件操作符和条件表达式

条件操作符(?:)是三目操作符,它根据关系表达式或逻辑表达式的值来选择其他表达式的结果作为整个表达式的结果,由条件操作符、条件表达式和值连接起来的表达式称为条件表达式。它的一般书写格式为:

其中,表达式expression1一般为关系表达式或逻辑表达式,如果该值为true,则将表达式expression2的结果作为整个条件表达式的结果,如果该值为false,则将表达式expression3的结果作为整个条件表达式的结果。

例如:存在条件表达式7>5?"abc":'a'+'b',首先计算关系表达式7>5的值为true,则将"abc"作为整个表达式的结果,否则将'a'+'b'作为整个表达式的结果。

条件操作符和条件表达式如表2-10所示。

表2-10 条件操作符和条件表达式

2.2.7 其他操作符和相关表达式

Java语言中除了上述常用的操作符和表达式之外,还有连接运算符(+)、引用操作符(.)和instanceof操作符等,这些操作符在编程过程中也经常用到。

1.连接操作符和连接表达式

连接操作符(+)是双目操作符,它是对算术操作符(+)的扩展,能够对字符串进行连接,连接起来的表达式称为连接表达式。例如:"国家"+"公民"的结果为"国家公民"。

连接操作符(+)还可以将字符串与其他类型的数据进行连接,结果是字符串。例如:"国家"+6.0的结果为"国家6.0",6.0+"国家"的结果为"6.0国家"。

一般来说,如果连接操作符(+)的第一个操作数是字符串,则Java编译器会自动将后续的操作数类型转换成字符串类型,然后再进行连接。如果连接操作符(+)的第一个操作数不是字符串,则计算结果由后续的操作数决定。例如:5+3+7+"国家"的结果为"15国家",而不是"537国家"。再如:"国家"+5+3+7的结果为"国家537",而"国家"+(5+3+7)的结果则为"国家15"。

2.引用操作符和引用表达式

引用操作符(.)是双目操作符,它是面向对象程序设计中常用的操作符,用来实现对象引用其变量和方法。由引用操作符和变量或方法连接起来的表达式称为引用表达式。

引用操作符(.)表示了一种隶属关系。例如:System.out.println("Hello"),就表示System引用了out对象,out对象引用了方法println("Hello"),即out对象隶属于System,println("Hello")方法隶属于out对象。

3.instanceof操作符和instanceof表达式

instanceof操作符是双目操作符,它是用来判断一个对象是否是指定类或其子类的实例,由instanceof操作符、对象和类连接起来的表达式称为instanceof表达式。

instanceof操作符是面向对象程序设计中常用的操作符,instanceof表达式的计算结果是boolean值。例如:aSwallow instanceof Bird的结果为true,而aSwallow instanceof Dog的结果为false。

其他操作符和相关表达式如表2-11所示。

表2-11 其他操作符和相关表达式

2.2.8 操作符的优先级和复杂表达式

Java语言的基本单元是表达式,最简单的表达式是一个常量或一个变量,该表达式的值就是该常量或变量的值。表达式的值还可以作为其他运算的操作数,当表达式中含有两个或两个以上的操作符时,该表达式称为复杂表达式。在对一个复杂表达式进行运算时,操作符的优先级决定了表达式中不同运算执行的先后次序,优先级高的先进行运算,优先级低的后进行运算,同级操作符则按照在表达式中出现的位置按结合性的方向进行结合运算。Java语言操作符的优先级和结合性如表2-12所示。

表2-12 Java语言操作符的优先级和结合性

续表