学习目标:掌握Java表达式运算的各类运算符,具体包括算术运算符、赋值运算符、逻辑运算符和关系运算符。
表达式
表达式是由变量或常量与符号的组合,例如:num1+num2或age>18等。表达式中常用的符号称为运算符,这些运算符作用的变量或常量称为操作数。例如:在表达式age>18中,age和18是操作数,符号>为运算符。同样,在表达式num1+num2中,num1和num2均为操作数,符号+为算术运算符。在一些复杂的运算中,简单的表达式可以组合为复杂的表达式,其操作数本身可能就是一个表达式。例如(num1+num2)*(x+y),其中的操作数(num1+num2)和(x+y)本身就是表达式,并用运算符*相乘。
表达式的计算结果必须是一个值,如果表达式是一个条件,就会产生逻辑值结果,即真或假。在其他情况下,值通常为计算的结果。
Java语言中合法的表达式
① a*b+2
其中,a、b、2为操作数,a和b为变量,2为数值常量,+为运算符
② ‘a’ + 3
其中,‘a’为字符常量,参与计算时其数值为该字符所在字符集的编码值,‘a’为ASCII吗是,表达式‘a’ + 3等同于97+3
③ “study” + “java”
其中,“study”和“java”为字符串常量,+为运算符,如果运算符+两边的操作数都为字符串常量,其计算结果是两个字符串常量的连接,该表达式运算结果为” study java”
Java语言中表达式的分类
表达式可分为多种类别,具体取决于所用运算符的类型。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。
表中条件表达式的运算符==、!=、>、<、>=、<=,分别对应等于、不等于、大于、小于、大于等于、小于等于运算。
表中逻辑表达式的运算符&、|、^、&&、||、!,分别对应与、或、异或、相与、相或、逻辑非运算。
表达式是由一个或多个操作数通过运算符组合而成。最简单的表达式仅由一个运算符和一个操作数构成,较复杂的表达式则由多个运算符以及多个操作数构成。表达式的计算结果为一个值,如果是逻辑运算表达式,其计算结果为逻辑值结果,即真或假。
算术运算符
算术运算符用在算术表达式中,其作用和数学中的运算符相同,下表列出了Java语言支持的算术运算符。
案例8:在Punit2项目unit包下创建Case8类,代码如下:
package com.unit;
public class Case8 {
public static void main(String[] args) {
// +运算符演示
int a = 20;
int b = 10;
//a与b相加的结果赋值给声明的整型变量sum
int sum = a+b;
System.out.println("a+b =" + sum);
// -运算符演示
//a与b相减的结果赋值给声明的整型变量sub
int sub = a-b;
System.out.println("a-b =" + sub);
// *运算符演示
//a与b相乘的结果赋值给声明的整型变量sub
int muliti = a*b;
System.out.println("a*b =" + muliti);
// / 运算符演示
//a与b相除的结果赋值给声明的整型变量sub
int div = a/b;
System.out.println("a/b =" + div);
}
}
程序功能主要是演示+、-、*、/运算符的使用方法。
程序声明了a和b两个变量,并分别赋值为20和10,后面代码的运算表达式都用到了已声明的a和b两个变量。
取余运算符
取余运算符是双目运算符,运算结果是运算符左边的操作数除以运算符右边的操作数后所得的余数。例如:10%8=2、15%5=0等。
假设 a % b =c(余数为d),其中a和b均为整数,则余数d为a % b的结果。
自增自减运算符
自增自减是单目运算符,只需要一个操作数参加运算。例如:a++、++a、a--、--a等。其中,a是操作数,++是自增运算符,--是自减运算符,自增和自减运算符即可以放在变量的前面,也可以放在变量的后面,例如++a、 a++。
自增(++):将变量的值加1,分前缀式(如++a)和后缀式(如a++)。前缀式是先加1再使用;后缀式是先使用再加1。
例如:
int a=10;
System.out.println("a=" + a++);
上述语句执行结果为:a=10,为什么不是11呢?自增后缀式是先使用再自增,因此先输出a的当前数值,然后a再做加1操作。
int a=10;
System.out.println("a=" + ++a);
上述语句执行结果为:a=11,自增前缀式是先自增再使用,变量a先做加1操作,然后再输出。
自减(--):将变量的值减1,分前缀式(如--a)和后缀式(如a--)。前缀式是先减1再使用;后缀式是先使用再减1。
例如:
int a=10;
System.out.println("a=" + a--);
上述语句执行结果为:a=10,为什么不是9呢?自减后缀式是先使用再自减,因此先输出a的当前数值,然后a再做减1操作。
int a=10;
System.out.println("a=" + --a);
上述语句执行结果为:a=9,自减前缀式是先自减再使用,变量a先做减1操作,然后再输出。
简单赋值运算符
简单赋值运算符为双目运算符,运算符左边的操作数为被赋值的变量,右边的操作数为值或表达式,值可以为常量、变量或数值,表达式为由变量或常量、数值与运算符的组合,若右边的操作数为表达式,需先计算表达式,再将表达式的结果赋值给左边操作数所指向的变量。
下表列出了Java语言支持的简单赋值运算符。
复合赋值运算符
复合赋值是指先执行运算符指定的运算,然后再将运算结果存储到运算符左边操作数指定的变量中。下表列出了“+=、-=、*=、/=、%=”复合赋值运算符的描述及例子。
复合赋值运算符同简单赋值运算符一样,也是双目运算符,需要两个操作数。不同的是,复合赋值运算符要先执行运算符自身要求的运算后,再将运算后的结果赋值给左边的操作数指定的变量。
复合赋值运算符“+=”,表示的意思是先将运算符左边操作数指向的变量值和右边的操作数执行相加操作,然后再将相加的结果赋值给左边的操作数指向的变量。例如下面语句:
int a = 10;
a += 20;
此时,变量a等于30,其过程是变量a先与数值20相加,因为变量a的值是10,因此与数值20相加的结果是30,再将30赋值给变量a,此时变量a的值为30。
复合赋值运算符“-=”,表示的意思是先将运算符左边操作数指向的变量值和右边的操作数执行相减操作,然后再将相减的结果赋值给左边的操作数指向的变量。例如下面语句:
int a = 20;
a -= 18;
此时,变量a等于2,其过程是变量a先与数值18相减,因为变量a的值是20,因此与数值18相减的结果是2,再将2赋值给变量a,此时变量a的值为2。
复合赋值运算符“*=”,表示的意思是先将运算符左边操作数指向的变量值和右边的操作数执行相乘操作,然后再将相乘的结果赋值给左边的操作数指向的变量。例如下面语句:
int a = 20;
a *= 3;
此时,变量a等于60,其过程是变量a先与数值3相乘,因为变量a的值是20,因此与数值3相减的结果是60,再将60赋值给变量a,此时变量a的值为60。
复合赋值运算符“/=”,表示的意思是先将运算符左边操作数指向的变量值和右边的操作数执行相除操作,然后再将相除的结果赋值给左边的操作数指向的变量。例如下面语句:
int a = 15;
a /= 3;
此时,变量a等于5,其过程是变量a先与数值3相除,因为变量a的值是15,因此与数值3相除的结果是5,再将5赋值给变量a,此时变量a的值为5。
复合赋值运算符“%=”,表示的意思是先将运算符左边操作数指向的变量值和右边的操作数执行取余操作,然后再将取余的结果赋值给左边的操作数指向的变量。例如下面语句:
int a = 15;
a %= 8;
此时,变量a等于7,其过程是变量a先与数值8执行取余运算,因为变量a的值是15,因此与数值8取余运算的结果是7,再将7赋值给变量a,此时变量a的值为7。
案例9:在Punit2项目unit包下创建Case9类。代码如下:
package com.unit;
public class Case9 {
public static void main(String[] args) {
// +=运算符示例,声明变量a且初始化为10
int a = 10;
a += 20;
System.out.println("a += 20:" + a);
// -=运算符示例,声明变量b且初始化为20
int b = 20;
b -= 18;
System.out.println("b-=18:" + b);
// *=运算符示例,声明变量c且初始化为20
int c = 20;
c *= 3;
System.out.println("c*=3:" + c);
// /=运算符示例,声明变量d且初始化为15
int d = 15;
d /= 3;
System.out.println("d/=3:" + d);
// %=运算符示例,声明变量e且初始化为15
int e = 15;
e %= 8;
System.out.println("e%=3:" + e);
}
}
移位赋值运算符
显示器显示的虽然是我们熟悉的十进制或字符,但在计算机存储器存储的数据都是以二进制形式存储的,程序输出时通过转换程序把二进制数据转换为十进制或字符输出到屏幕上。二进制数是用0和1两个数字来表示的数,一个byte类型的数据占一个字节,是8位二进制数,一个int类型的数据占2个字节,是16位位二进制数。例如:字符A的十进制表示是65,二进制表示是01000001。位运算符就是针对二进制位进行操作,下表列出了位运算符“<< =、>>=”的描述及例子。
左移赋值运算符
左移赋值运算符用“<< =”表示,是将运算符左边操作数指定的变量值,向左移动运算符右边指定的位数,左侧移除的位全部丢弃,并且在低位补零后,再赋值给运算符左边操作数指定的变量。左移运算结果不能溢出,溢出后原来的数据信息会丢失。
溢出示例:字符A的ASCII编码十进制数值为65,二进制编码是01000001,左侧第二位为1,如果左移2位,其值为00000100,其左侧的1被移除,运算结果溢出,移位后的数据无意义。因此,在左移运算过程中,只有为1的位没被移除,移位后的运算结果才有意义。
未溢出示例:数字1的ASCII编码为00110001,十进制数值为49,左移1位后,其值为01100010,十进制数值为98,其ASCII吗对应的字符为b。
从上个例子可以看出,在无溢出的情况下,数值向左移n 位,就相当于乘上2 的n 次方。
右移赋值运算符
右移赋值运算符用“〉〉 =”表示,是将运算符左边操作数指定的变量值,向右移动运算符右边指定的位数,右侧移除的位全部丢弃,左侧留出的空位补上符号位(正数为0,负数为1),再赋值给运算符左边操作数指定的变量。
例如:字符A的ASCII编码十进制数值为65,二进制编码是01000001,右移2位后,其值为00010000,十进制数值为16,如果右移8或更高位数,二进制编码为00000000,其数值为0,无实际意义。
案例10:在Punit2项目unit包下创建Case10类。代码如下:
package com.unit;
public class Case10 {
public static void main(String[] args) {
// 溢出左移运算符
char a = 'A';
// 将变量a左移2位
a <<= 2;
System.out.printf("a =%d\n", (int) a);
// 未溢出左移运算
char c = '1';
// 将变量c左移1位
c <<= 1;
System.out.printf("c =%d\n", (int) c);
}
}
关系运算符
关系运算符是双目运算符,用在条件表达式中。用于判断两个数据之间的关系,例如:大于、等于、不等于,比较的结果是一个布尔值( true 或 false )。下表列出了Java语言支持的比较运算符,表中例子假设A和B不相等其A小于B。
关系运算符“==”,用于判断运算符两边的操作数是否相等,如果相等,返回结果为true,否则返回false。例如下面语句:
int a = 10;
int b = 20;
boolean bJudge = a == b;
声明了变量a和变量b,分别赋值为10和20,第三条语句判断变量a和变量b的值是否相等,并把判断结果赋值给布尔类型的变量bJudge,由于关系运算符“==”优先级高于赋值运算符“=”,因此,语句执行顺序是先判断再赋值。此时bJudge的值为false。
关系运算符“!=”,用于判断运算符两边的操作数是否相等,如果不相等,返回结果为true,否则返回false。例如下面语句:
int a = 10;
int b = 20;
boolean bJudge = a != b;
因为变量a和变量b的值不相等,语句执行完后,bJudge的值为true。
关系运算符“〉”,用于判断运算符左边的操作数是否大于运算符右边的操作数,如果大于,返回结果为true,否则返回false。例如下面语句:
int a = 10;
int b = 20;
boolean bJudge = a 〉 b;
因为变量a的值小于变量b的值,语句执行完后,bJudge的值为false。
关系运算符“<”,用于判断运算符左边的操作数是否小于运算符右边的操作数,如果小于,返回结果为true,否则返回false。例如下面语句:
int a = 10;
int b = 20;
boolean bJudge = a < b;
因为变量a的值小于变量b的值,语句执行完后,bJudge的值为true。
关系运算符“>=”,用于判断运算符左边的操作数是否大于或者等于运算符右边的操作数,如果大于或者等于,返回结果为true,否则返回false。例如下面语句:
int a = 10;
int b = 20;
boolean bJudge = a >= b;
因为变量a的值小于变量b的值,语句执行完后,bJudge的值为false。
关系运算符“<=”,用于判断运算符左边的操作数是否小于于或者等于运算符右边的操作数,如果小于或者等于,返回结果为true,否则返回false。例如下面语句:
int a = 10;
int b = 20;
boolean bJudge = a <= b;
因为变量a的值小于变量b的值,语句执行完后,bJudge的值为true。
逻辑运算符
逻辑运算符用于连接两个条件表达式或布尔类型的变量,用于执行多个判断。在数学中,表示一个数值的范围时,经常用不等式来表述。例如:假设一个数值取值范围为0到100,设该数值为x,不等式0<x<100给出了x的取值范围,在Java程序语言中,逻辑运算符可以实现类似数学中的不等式。下表列出了Java语言支持的逻辑运算符,表中假设布尔变量A为真,变量B为假。
逻辑与运算符“&&”,用于判断运算符两边的条件表达式或布尔变量是否同为真,如果同为真,返回结果为true,否则返回false。例如下面语句:
int a = 10;
int b = 20;
int c = 15;
boolean bJudge = c > a && c < b;
声明了变量a、变量b、变量c,变量a和变量分别赋值为10和20,变量c赋值为15。第四条语句逻辑与运算符“&&”连接了2个条件表达式,分别是c > a和c < b,如果这两个表达式计算结果都为真,则bJudge为真,否则bJudge为false。此时bJudge的值为true。该运算符还有一个特点,当左侧的条件表达式或布尔变量为假时,则直接返回结果false,不再执行运算符右侧的表达式或布尔变量。
逻辑或运算符“||”,用于判断运算符两边的条件表达式或布尔变量是否有一个为真,如果有一个为真,返回结果为true,否则返回false。例如下面语句:
int a = 10;
int b = 20;
int c = 15;
boolean bJudge = c > a || c < b;
逻辑或运算符“||”连接了2个条件表达式,分别是c > a和c < b,这两个表达式计算结果任何一个为真时,则bJudge为真,否则bJudge为false。此时bJudge的值为true。
逻辑非运算符“!”,用于判断运算符两边的条件表达式或布尔变量是否有一个为真,如果有一个为真,返回结果为true,否则返回false。例如下面语句:
int a = 10;
int b = 20;
boolean bJudge = !( a> b);
逻辑非运算符“!”用于取反条件表达式a> b的结果,如果a> b为真,取反后为false,如果a> b为假,取反后为true。此时bJudge的值为true。语句中用括号把a> b括起来,用于提高a> b的优先级,先计算a> b,再取反。
逻辑赋值运算符
在二进制运算中,除了左移赋值运算和右移赋值运算外,还有与运算赋值(&=)、异或运算赋值(^ =)、或运算赋值(| =),下表列出了位运算符“&=、^ =、| =”的描述及例子。
与运算赋值
与运算是二进制数按位做相与运算再赋值,其运算规则是:
0&0=0; 0&1=0; 1&0=0; 1&1=1
即:两位同时为1,结果才为1,否则为0。
参与与运算的两个操作数,位数必须相同,也就是数据类型必须相同。不同类型的数据做与运算,需要强制转换为同一类型。
例如:数据类型同为int的数值8和14与运算的结果依然是8,下图给出了与运算过程,int类型的数据是16位,因为高8位都是0,因此下图只列出了低8位的运算过程:

从图中可以看出,两个数值做与运算,相同位同时为1时,结果为1,其它都为0。
异或运算赋值
异或运算是二进制数按位做异或运算再赋值,其运算规则是:
0^0=0; 0^1=1; 1^0=1; 1^1=0
即:如果两个相应位为“异”(值不同),则该位结果为1,否则为0。
同与运算相同,参与与运算的两个操作数,位数必须相同,也就是数据类型必须相同。不同类型的数据做与运算,需要强制转换为同一类型。
例如:数据类型同为int的数值8和14异或运算的结果是6,下图给出了异或运算过程,int类型的数据是16位,因为高8位都是0,因此下图只列出了低8位的运算过程:

从上图结果可以看出,两个数值做异或运算,相同位不同时结果为1,其它都为0。
或运算赋值
或运算是二进制数按位做或运算再赋值,其运算规则是:
0|0=0; 0|1=1; 1|0=1; 1|1=1
即:两位只要有一个为1,其值为1,其它都为0。
同与运算相同,参与与运算的两个操作数,位数必须相同,也就是数据类型必须相同。不同类型的数据做与运算,需要强制转换为同一类型。
例如:数据类型同为int的数值8和14异或运算的结果是14,下图给出了或运算过程,int类型的数据是16位,因为高8位都是0,因此下图只列出了低8位的运算过程:
从上图可以看出,两个数值做或运算,相同位只要有一个为1,其结果就为1,其它都为0。
运算符优先级
Java表达式可能存在多个运算符,运算符之间存在优先级的关系,级别高的运算符先执行运算,级别低的运算符后执行运算算,下表列出了运算符的优先级。表中优先级栏,数字越小优先级越高,运算符每个运算符用中文顿号分割。

表中结合性指运算符结合的顺序,通常都是从左到右。从右到左的运算符最典型的就是数值前面的正负号,例如3+-4,则意义为3加-4,符号首先和运算符右侧的内容结合。
表中运算符‘[]’前面没有讲到,该运算符表示声明一个数组,关于数组后面会详细讲述。
表中小括号‘()’优先级最高,表达式含有小括号的,优先执行小括号的内容,如果包含多个小括号,执行顺序是从左到右。
例如,假设变量a的值为12,下述语句的执行会有不同的结果:
(1)执行 a + 18 % 4 ,因为运算符%的优先级高于运算符+,该语句先执行取余运算,再执行加法运算,其结果为14;
(2)执行( a + 18 ) % 4 ,因为小括号的优先级最高,该语句先执行小括号里的表达式a+18,再执行取余运算,其结果为2;
(3)执行 a * ( ( a + 18 ) % 4 ),该语句括号内嵌套括号,执行顺序是先执行内层括号的运算,再执行外层括号的运算,其运算结果为24。
案例11:在Punit2项目unit包下创建Case11类。代码如下:
package com.unit;
public class Case11 {
public static void main(String[] args) {
// 声明变量a和b并赋值
int a = 10;
int b = 4;
// 执行运算
a += ++b;
System.out.printf("a =%d\n", a);
System.out.printf("b =%d\n", b);
}
}
代码结构分析
程序功能主要是演示运算符的优先级。
语句“a += ++b;”,涉及到运算符+=和++两个运算符,从运算符优先级表可知,++运算符的优先级要高于+=运算符,b应先做自增运算,然后再与a相加,结果为15。一个特例是,语句“a += b++;”,虽然++的优先级高于+=,但此语句的++是后缀式,后缀式是先使用再自增,因此,b先与a相加后,再做自增运算,结果为15。