对数据进行加工的过程称为运算,表示各种不同运算的符号称为运算符。Java提供丰富的运算符,如赋值运算符、算术运算符、关系运算符等。本节向读者介绍这些运算符。
赋值运算符以符号“=”表示,它是一个二元运算符(对两个操作数作处理),其功能是将右方操作数所含的值赋给左方的操作数。例如如下代码。
int a = 100;
该表达式是将100赋值给变量a。左方的操作数必须是一个变量,而右边的操作数则可以是任何表达式,包括变量。
Java算术运算符主要有+(加)、-(减)、*(乘)、/(除)、%(求余)。它们都是二元运算符。另外,还有一些单目运算符,如++(自增)和--(自减)运算符。Java运算符的功能及使用方式如表2-4所示。需要说明的是,表中的变量a为整型变量。
表2-4 算术运算符
Java算术运算符的优先级如表2-5所示。
表2-5 算术运算符的优先级
在算术运算符中比较难于理解的是“++”和“--”运算符,下面对这两个运算符较为详细地介绍。
自增和自减运算是两个快捷运算符(常称作“自动递增”和“自动递减”运算)。其中,自减操作符是“--”,意为“减少一个单位”;自增操作符是“++”,意为“增加一个单位”。例如,a是一个int变量,则表达式++a等价于a=a+1。递增和递减操作符不仅改变变量,并且以变量的值作为生成的结果。
这两个操作符各有两种使用方式,通常称为“前缀式”和“后缀式”。“前缀递增”指++操作符位于变量的前面;而“后缀递增”指++操作符位于变量的后面。“前缀递减”指--操作符位于变量的前面;而“后缀递减”指--操作符位于变量的后面。
对于前缀递增和前缀递减(如++a或--a),会先执行运算,再生成值。而对于后缀递增和后缀递减(如a++或a--),是先生成值,再执行运算。下面是一个有关“++”运算符的例子。
【例2-9】++运算符在程序中的使用。
public class AutoInc {
public static void main(String[] args) {
int i = 1;
int j = 1;
System.out.println("i后缀递增的值= " + (i++)); //后缀递增
System.out.println("j前缀递增的值= " + (++j)); //前缀递增
System.out.println("最终i的值 =" + i);
System.out.println("最终j的值 =" + j);
}
}
程序执行结果如图2-2所示。
图2-2 例2-9的运行结果
从运行结果中可以看到,放在变量前面的自增运算符,先将变量的值加1,然后再使该变量参与其他运算。放在变量后面的自增运算符,先使变量先参与其他运算,然后再将该变量加1。
关系运算实际上就是“比较运算”。将两个值进行比较,判断比较的结果是否符合给定的条件。如果符合则表达式的结果为true,否则为false。
Java关系运算符都是二元运算符。由Java关系运算符组成的关系表达式的计算结果为逻辑值。具体的关系运算符及其说明见表2-6所示。
表2-6 比较运算符
【例2-10】使用比较运算符对变量进行比较,并将运算后的结果输出。
public class Compare {
public static void main(String[] args) {
int x = 21;
int y = 100;
//依次将变量x与变量y的比较结果输出
System.out.println("x >y返回值为:"+ (x > y));
System.out.println("x <y返回值为:"+ (x < y));
System.out.println("x==y返回值为:"+ (x== y));
System.out.println("x!=y返回值为:"+ (x != y));
System.out.println("x>=y返回值为:"+ (x >= y));
System.out.println("x<=y返回值为:"+ (x <= y));
}
}
程序执行结果如图2-3所示。
图2-3 例2-10的运行结果
Java语言逻辑运算符有三个,分别是&&(逻辑与)、||(逻辑或)、!(逻辑非),其中前两个是双目运算符,第三个为单目运算符。具体的运算规则如表2-7所示。
表2-7 逻辑运算符
【例2-11】逻辑运算符在程序中的应用。
public class CLoperation {
public static void main(String[] args){
boolean a = true;
boolean b = false;
System.out.println("a && b = " + (a && b));
System.out.println("a || b = " + (a || b));
System.out.println("!(a && b) = " + !(a && b));
}
}
程序执行结果如图2-4所示。
图2-4 例2-11的运行结果
特别地,当使用逻辑与运算符时,在两个操作数都为true时,结果才为true。但是当得到第一个操作数为false时,其结果就必定是false,这时候就不会再判断第二个操作数。这称作短路逻辑运算符,如例2-12。
【例2-12】短路逻辑运算符的应用。
public class LuoJi {
public static void main(String[] args) {
int a = 5;//定义一个变量;
boolean b = (a<4)&&(a++<10);
System.out.println("使用短路逻辑运算符的结果为"+b);
System.out.println("a的结果为"+a);
}
}
执行结果如图2-5所示。
图2-5 例2-12的运行结果
该程序使用到了短路逻辑运算符(&&),首先判断a<4的结果为false,则b的结果必定是false,不再执行第二个操作a++<10的判断,所以a的值为5。
位运算符用来对二进制的位进行操作,其操作数的类型是整数类型以及字符类型,运算结果是整型数据。
整型数据在内存中以二进制的形式表示,如int型变量7的二进制表示是00000000 00000000 00000000 00000111。其中,左边最高位是符号位,最高位是0表示正数,若为1则表示负数。负数采用补码表示,如-8的二进制表示为111111111 111111111 1111111 11111000。
了解了整型数据在内存中的表示形式后,开始学习位运算符。
“按位与”运算符“&”为双目运算符,其运算法则是将参与运算的数转换成二进制数,然后低位对齐,高位不足补零,如果对应的二进制位都是1,则结果为1,否则结果为0。
使用按位与运算符的示例如下。
int a = 3; //0000 0011
int b = 5; //0000 0101
int c = a&b; //0000 0001
按照按位与运算的计算规则,3&5的结果是1。
“按位或”运算符“|”为双目运算符。“按位或”运算的运算法则是将参与运算的数转换成二进制数,然后低位对齐,高位不足补零,如果对应的二进制位只要有一个为1,则结果为1,否则结果为0。
使用按位或运算符的示例如下。
int a = 3; //0000 0011
int b = 5; //0000 0101
int c = a|b; //0000 0111
按照按位或运算的计算规则,3|5的结果是7。
“按位异或”运算符“^”为双目运算符。“按位异或”运算的运算法则是将参与运算的数转换成二进制数,然后低位对齐,高位不足补零,如果对应的二进制位相同,则结果为0,否则结果为1。
使用按位异或运算符的示例如下。
int a = 3; //0000 0011
int b = 5; //0000 0101
int c = a^b; //0000 0110
按照按位异或运算的计算规则,3^5的结果是6。
“按位取反”运算符“~”为单目运算符。“按位取反”运算的运算法则:先将参与运算的数转换成二进制数,然后把各位的1改为0,0改为1。
使用按位取反运算符的示例如下。
int a = 3; //0000 0011
int b = ~ a; //0000 1100
按照按位取反运算的计算规则,~3的结果是-4。
“右移位”运算符“>>”为双目运算符。“右移位”运算的运算法则:先将参与运算的数转换成二进制数,然后所有位置的数统一向右移动对应的位数,低位移出(舍弃),高位补符号位(正数补0,负数补1)。
使用右移位运算符的示例如下。
int a = 3; //0000 0011
int b = a>>1; //0000 0001
按照右移位运算的计算规则,3 >>1的结果是1。
“左移位”运算符“<<”为双目运算符。“左移位”运算的运算法则:先将参与运算的数转换成二进制数,然后所有位置的数统一向左移动对应的位数,高位移出(舍弃),低位的空位补0。
使用左移位运算符的示例如下。
int a = 3; //0000 0011
int b = a<<1; //0000 0110
按照左移位运算的计算规则,3 <<1的结果是6。
“无符号右移位”运算符“>>>”为双目运算符。“无符号右移位”运算的运算法则:先将参与运算的数转换成二进制数,然后所有位置的数统一向右移动对应的位数,低位移出(舍弃),高位补0。
使用无符号右移位运算符的示例如下。
int a = 3; //0000 0011
int b = a>>>1; //0000 0001
按照无符号右移位运算的计算规则,3 >>>1的结果是1。
【例2-13】位运算符的使用。
public class BitOperation {
public static void main(String[] args) {
int i = 3;
int j = 5;
System.out.println("i&j的值为:" + (i&j));
System.out.println("i|j的值为:" + (i|j));
System.out.println("i^j的值为:" + (i^j));
System.out.println("~i的值为:" + (~i));
System.out.println("i>>1的值为:" + (i>>1));
System.out.println("i<<1的值为:" + (i<<1));
}
}
程序执行结果如图2-6所示。
图2-6 例2-13的运行结果
条件运算符“? :”需要三个操作数,所以又被称为三元运算符。条件运算符的语法规则如下。
<布尔表达式> ? value1:value2
如果“布尔表达式”的结果为true,返回value1的值。如果“布尔表达式”的结果为false,则返回value2的值。
使用条件运算符的示例如下。
int a = 3;
int b = 5;
int c = (a > b)? 1:2;
按照条件运算符的计算规则,执行后c的值为2。
当多个运算符出现在一个表达式中,谁先谁后呢?这就涉及运算符的优先级的问题。
Java语言规定了运算符的优先级与结合性。在表达式求值时,先按照运算符的优先级由高到低的次序执行。例如,算术运算符中的乘、除运算优先于加、减运算。
对于同优先级的运算符要按照它们的结合性来决定。运算符的结合性决定它们是从左到右计算(左结合性)还是从右到左计算(右结合性)。左结合性很好理解,因为大部分的运算符都是从左到右来计算的。需要注意的是右结合性的运算符,主要有3类:赋值运算符(如“=”、“+=”等)、一元运算符(如“++”、“!”等)和三元运算符(即条件运算符)。表2-8列出各运算符优先级的排列与结合性,请读者参考。
表2-8 运算符的优先级与结合性
因为括号优先级最高,所以不论任何时候,当无法确定某种计算的执行次序时,可以使用加括号的方法来明确指定运算的顺序。这样不容易出错,同时也是提高程序可读性的一个重要方法。