声明:原文出处已在文末标出,本人出于学习,对其做了整理,收集干货,不作商业用途!
Java 语言中的运算符除了具有优先级之外,还有一个结合性的特点。当一个表达式中出现多种运算符时,执行的先后顺序不仅要遵守运算符优先级别的规定,还要受运算符结合性的约束,以便确定是自左向右进行运算还是自右向左进行运算。这些运算符按照操作数的数量可以分为单目运算符、双目运算符和三目运算符。
最基本的运算符包括算术运算符、赋值运算符、逻辑运算符和关系运算符等。
Java算数运算符
Java 语言中算术运算符的功能是进行算术运算,除了经常使用的加(+)、减(-)、乘(*)和除(\)外,还有取余运算(%)。加(+)、减(-)、乘(*)、除(\)和我们平常接触的数学运算具有相同的含义。求余运算(%)是指连接两个变量或常量以进行除法运算,结果取它们的余数。
算术运算符都是双目运算符,即连接两个操作数的运算符。优先级上,*、/、% 具有相同运算级别,并高于 +、-(+、- 具有相同级别)。如果在一个表达式中的多个算术运算符的优先级别相同,例如“a-b+c”,此时将按照运算符的结合方向决定顺序。算术运算符的结合方向都是“从左至右”,即先左后右。
进行算术运算时应注意以下两点:
- 求余(%)运算要求参与运算的两个操作数均为整型,不能为其他类型。
- 两个整数进行除法运算,其结果仍为整数。如果整数与实数进行除法运算,则结果为实数。
例如:
①int x=2,y=1; 表达式 y/x 的结果是 0。
②float x=2.0f; int y=1; 表达式 y/x 的结果是 0.5。
在 ① 中整型变量 x 和 y 相除,其结果仍为整型数据 0;在 ② 中由于两个不同类型的数据进行运算,此时首先要进行类型转换,会把 int 型的 y 转换成与 x 一样的 float 型,然后相除,最终结果为 float 类型的数字 0.5。
Java赋值运算符(=)
赋值运算符是指为变量或常量指定数值的符号。赋值运算符的符号为“=”,它是双目运算符,左边的操作数必须是变量,不能是常量或表达式。
其语法格式如下所示:
变量名称=表达式内容
在 Java 语言中,“变量名称”和“表达式”内容的类型必须匹配,如果类型不匹配则需要转化为对应的类型。
赋值运算符的优先级低于算术运算符,结合方向是自右向左;不是数学中的等号,它表示一个动作,即将其右侧的值送到左侧的变量中(左侧只允许是变量,不能是表达式或其他形式);不要将赋值运算符与相等运算符“==”混淆。
赋值运算符与其他运算符一起使用,可以表达多种赋值运算的变异效果。赋值运算符和算数运算符组成的复合赋值运算的含义及其使用实例如表 1 所示。
运算符 | 含义 | 实例 | 结果 |
---|---|---|---|
+= | 将该运算符左边的数值加上右边的数值, 其结果赋值给左边变量本身 | int a=5; a+=2; | a=7 |
-= | 将该运算符左边的数值减去右边的数值, 其结果赋值给左边变量本身 | int a=5; a-=2; | a=3 |
*= | 将该运算符左边的数值乘以右边的数值, 其结果赋值给左边变量本身 | int a=5; a*=2; | a=10 |
/= | 将该运算符左边的数值整除右边的数值, 其结果赋值给左边变量本身 | int a=5; a/=2; | a=2 |
%= | 将该运算符左边的数值除以右边的数值后取余,其结果赋值给左边变量本身 | int a=5; a%=2; | a=1 |
Java逻辑运算符
逻辑运算符把各个运算的关系表达式连接起来组成一个复杂的逻辑表达式,以判断程序中的表达式是否成立,判断的结果是 true 或 false。
逻辑运算符包括 &&、||、!。其中 && 和 || 是双目运算符,实现逻辑与、逻辑或;!是单目运算符,实现逻辑非。表 1 给出了逻辑运算符的用法、含义及实例。
运算符 | 用法 | 含义 | 结合方向 | 实例 | 结果 |
---|---|---|---|---|---|
&& | op1&&op2 | 逻辑与 | 自左到右 | 2>1&&3<4 | true |
II | op1||op2 | 逻辑或 | 自左到右 | 2<1||3>4 | false |
! | !op | 逻辑非 | 自右到左 | !(2>4) | true |
结果为 boolean 型的变量或表达式可以通过逻辑运算符结合成为逻辑表达式。逻辑运算符 &&、|| 和 !按表 2 进行逻辑运算。
op1 | op2 | op1&&op2 | op1||op2 | !op1 |
---|---|---|---|---|
true | true | true | true | false |
false | true | false | true | true |
true | false | false | true | false |
false | false | false | false | true |
逻辑运算符的优先级为:!运算级别最高,&& 运算高于 || 运算。!运算符的优先级高于算术运算符,而 && 和 || 运算则低于关系运算符。结合方向是:逻辑非(单目运算符)具有右结合性,逻辑与和逻辑或(双目运算符)具有左结合性。
Java关系运算符
关系运算符用来比较两个值的关系。关系运算符是二元运算符,运算结果是 boolean 型。当运算符对应的关系成立时,运算结果是 true,否则是 false。
关系表达式是由关系运算符连接起来的表达式。关系运算符中“关系”二字的含义是指一个数据与另一个数据之间的关系,这种关系只有成立与不成立两种可能情况,可以用逻辑值来表示,关系成立时表达式的结果为 true(或 1),否则表达式的结果为 false(或 0)。表 1 给出了比较运算符的含义及其实例应用:
运算符 | 含义 | 实例 | 结果 |
---|---|---|---|
> | 大于运算符 | 2>3 | false |
>= | 大于或等于运算符 | 4>=2 | true |
< | 小于运算符 | 2<3 | true |
<= | 小于或等于运算符 | 4<=2 | false |
== | 相等运算符 | 4==4 | true |
!= | 不相等运算符 | 4!=2 | true |
关系运算符的优先级为:>、<、>=、<= 具有相同的优先级,并且高于具有相同优先级的 !=、==。关系运算符的优先级高于赋值运算符而低于算术运算符,结合方向是自左向右。
关系表达式通常用于 Java 程序的逻辑判断语句的条件表达式中。使用关系表达式要注意以下几点:
- 运算符 >=、==、!=、<= 是两个字符构成的一个运算符,用空格从中分开写就会产生语法错误。例如 x> =y; 是错误的,但是可以写成 x>=y; 在运算符的两侧增加空格会提高可读性。同样将运算符写反,例如 =>、=<、=! 等形式会产生语法错误。
- 由于计算机内存放的实数与实际的实数存在着一定的误差,如果对浮点数进行 ==(相等)或 !=(不相等)的比较,容易产生错误结果,应该尽量避免。
- 不要将“==”写成“=”。
Java自增和自减运算符(++和--)
在对一个变量做加 1 或减 1 处理时,可以使用自增运算符 ++ 或自减运算 --。++ 或 -- 是单目运算符,放在操作数的前面或后面都是允许的。++ 与 -- 的作用是使变量的值增 1 或减 1。操作数必须是一个整型或浮点型变量。自增、自减运算的含义及其使用实例如表 1 所示。
运算符 | 含义 | 实例 | 结果 |
---|---|---|---|
i++ | 将 i 的值先使用再加 1 赋值给 i 变量本身 | int i=1; int j=i++; | i=2 j=1 |
++i | 将 i 的值先加 1 赋值给变量 i 本身后再使用 | int i=1; int j=++i; | i=2 j=2 |
i-- | 将 i 的值先使用再减 1 赋值给变量 i 本身 | int i=1; int j=i--; | i=0 j=1 |
--i | 将 i 的值先减 1 后赋值给变量 i 本身再使用 | int i=1; int j=--i; | i=0 j=0 |
在使用自增/自减运算时应注意下面几个问题:
- 自增/自减只能作用于变量,不允许对常量、表达式或其他类型的变量进行操作。常见的错误是试图将自增或自减运算符用于非简单变量表达式中。
- 自增/自减运算可以用于整数类型 byte、short、int、long,浮点类型 float、double,以及字符类型 char。
- 在 Java 1.5 以上版本中,自增/自减运算可以用于基本类型对应的包装器类 Byte、Short、Integer、Long、Float、Double 和 Character。
- 自增/自减运算结果的类型与被运算的变量类型相同。
Java位运算符:Java移位运算符、复合位赋值运算符及位逻辑运算符
位运算符主要用来对操作数二进制的位进行运算。按位运算表示按每个二进制位(bit)进行计算,其操作数和运算结果都是整型值。Java 语言中的位运算符分为位逻辑运算符和位移运算符两类。
位逻辑运算符
位逻辑运算符包含 4 个:&(与)、|(或)、~(非)和 ^(异或)。除了 ~(即位取反)为单目运算符外,其余都为双目运算符。表 1 中列出了它们的基本用法。
运算符 | 含义 | 实例 | 结果 |
---|---|---|---|
& | 按位进行与运算 | 4 & 5 | 4 |
| | 按位进行或运算 | 4 | 5 | 5 |
^ | 按位进行异或运算 | 4 ^ 5 | 1 |
~ | 按位进行取反运算 | ~ 4 | -5 |
位与运算符
位与运算符为 &,其运算规则是:参与运算的数字,低位对齐,高位不足的补零,如果对应的二进制位同时为 1,那么计算结果才为 1,否则为 0。因此,任何数与 0 进行按位与运算,其结果都为 0。
例如下面的表达式:
100&0 图 1 所示为这个运算过程,结果为 0。
图1 100 位与 0 的运算过程
下面是两个非零的数字进行位与运算的过程。
- int x=5,y=12;//创建整型变量保存两个数
- int z=x&y;//对这两个数进行位与运算,结果保存到z
这两行语句执行后变量 Z 的值是 4,图 2 所示为这个运算过程。
图2 5 位与 12 的运算过程
位或运算符
位或运算符为 |,其运算规则是:参与运算的数字,低位对齐,高位不足的补零。如果对应的二进制位只要有一个为 1,那么结果就为 1;如果对应的二进制位都为 0,结果才为 0。
下面是一个使用位或运算符的表达式:
11|7 运算结果为 15,图 3 所示为其运算过程。
图3 11 位或 7 的运算过程
位异或运算符
位异或运算符为 ^,其运算规则是:参与运算的数字,低位对齐,高位不足的补零,如果对应的二进制位相同(同时为 0 或同时为 1)时,结果为 0;如果对应的二进制位不相同,结果则为 1。
下面是一个使用位异或运算符的表达式:
11^7 运算结果为 12,图 4 所示为其运算过程。
图4 11 位异或 7 的运算过程
提示:在有的高级语言中,将运算符 ^ 作为求幂运算符,要注意区分。
位取反运算符
位取反运算符为 ~,其运算规则是:只对一个操作数进行运算,将操作数二进制中的 1 改为 0,0 改为 1。
下面是一个使用位取反运算符的表达式:
~10 运算结果为 65525,图 5 所示为其运算过程。
图5 对 10 位取反的运算过程
我们可以使用如下的程序来检查这个运算结果:
- int i=10;
- System.out.printf("%d \n",~i);
编译执行以上程序,会发现输出的结果是 -11,而不是 65525。这是因为取反之后的结果是十六进制数,而在上面的程序中使用 %d 将输出转换为了十进制数。
可以使用如下语句查看十六进制结果。
- int i=10;
- System.out.printf("%x \n",~i);
可以看到输出结果为 fff5,将它转换为二进制是 1111111111110101。这个二进制数的最高位为 1,表示这个数为负数。除最高位外,按位取反再加 1,即得到二进制原码 1000000000001011,用十进制数表示即为 -11。
注意:位运算符的操作数只能是整型或者字符型数据以及它们的变体,不用于 float、double 或者 long 等复杂的数据类型。
位移运算符
位移运算符用来将操作数向某个方向(向左或者右)移动指定的二进制位数。它们都属于双目运算符。表 2 列出了 Java 语言中的两个位移运算符:
运算符 | 含义 | 实例 | 结果 |
---|---|---|---|
» | 右移位运算符 | 8»1 | 4 |
« | 左移位运算符 | 9«2 | 36 |
左位移运算符
左移位运算符为 «,其运算规则是:按二进制形式把所有的数字向左移动对应的位数,高位移出(舍弃),低位的空位补零。
例如,将整数 11 向左位移 1 位的过程如图 6 所示。
图6 对 11 左移 1 位运算过程
从图 6 中可以看到,原来数的所有二进制位都向左移动 1 位。原来位于左边的最高位 0 被移出舍弃,再向尾部追加 0 补位。最终到的结果是 22,相当于原来数的 2 倍。
右位移运算符
右位移运算符为 »,其运算规则是:按二进制形式把所有的数字向右移动对应的位数,低位移出(舍弃),高位的空位补零。
例如,将整数 11 向右位移 1 位的过程如图 7 所示。
图7 对 11 右移 1 位运算过程
从图 7 中可以看到,原来数的所有二进制位都向右移动 1 位。原来位于右边的最低位 1 被移出舍弃,再向最高位追加 0 补位。最终到的结果是 5,相当于原数整除 2 的结果。
复合位赋值运算符
复合位赋值运算符由赋值运算符与位逻辑运算符和位移运算符组合而成。表 3 列出了组合后的复合位赋值运算符。
运算符 | 含义 | 实例 | 结果 |
---|---|---|---|
&= | 按位与赋值 | num1 &= num2 | 等价于 num 1=num 1 & num2 |
\= | 按位或赋值 | num1 |= num2 | 等价于 num 1=num 1 | num2 |
^= | 按位异或赋值 | num1 ^= num2 | 等价于 num 1=num 1 ^ num2 |
~= | 按位取反赋值 | num1 ~= num2 | 等价于 num 1=num 1 ~ num2 |
«= | 按位左移赋值 | num1 «= num2 | 等价于 num 1=num 1 « num2 |
»= | 按位右移赋值 | num1 »= num2 | 等价于 num 1=num 1 » num2 |
Java条件运算符(?:)
条件运算符的符号为“?:”,使用该运算符时需要有三个操作数,因此称其为三目运算符。使用条件运算符的一般语法结构为:
- result=<expression>?<statement1>:<statement3>;
当 expression 为真时,执行 statement1, 否则就执行 statement3。此三目运算符要求返回一个结果,因此要实现简单的二分支程序,即可使用该条件运算符。
在使用条件运算符时,还应该注意优先级问题,例如下面的表达式:
- x>y ? x-=y : x+=y;
在编译时会出现语法错误,因为条件运算符优先于赋值运算符,上面的语句实际等价于:
- (x>y ? x-=y : x)+=y;
而运算符“+=”是赋值运算符,该运算符要求左操作数应该是一个变量,因此出现错误。为了避免这类错误,可以使用括号“0”来加以区分。例如,下面是正确的表达式。
- (x>y) ? (x-=y): (x+=y);
Java运算符优先级
Java 语言中运算符的优先级共分为 14 级,其中 1 级最高,14 级最低。在同一个表达式中运算符优先级高的先执行。表 1 列出了所有的运算符的优先级以及结合性。
优先级 | 运算符 | 结合性 |
---|---|---|
1 | ()、[] | 从左向右 |
2 | !、+、-、~、++、-- | 从右向左 |
3 | *、/、% | 从左向右 |
4 | +、- | 从左向右 |
5 | «、»、>>> | 从左向右 |
6 | <、<=、>、>=、instanceof | 从左向右 |
7 | ==、!= | 从左向右 |
8 | & | 从左向右 |
9 | ^ | 从左向右 |
10 | | | 从左向右 |
11 | && | 从左向右 |
12 | || | 从左向右 |
13 | ?: | 从右向左 |
14 | =、+=、-=、*=、/=、&=、|=、^=、~=、«=、»=、>>>= | 从右向左 |
使用优先级为 1 的小括号可以改变其他运算符的优先级,即如果需要将具有较低优先级的运算符先运算,则可以使用小括号将该运算符和操作符括起来。
来看一个复杂的表达式,如下所示:
--y || ++x && ++z;
这个表达式中包含了算术运算符和逻辑运算符。根据表 1 中列出的优先级,可以确定它的执行顺序如下:
① 先计算 y 的自减运算符,即 --y。
② 再计算 x 的自增运算符,即 ++x。
③ 接着计算 z 的自增运算符,即 ++z。
④ 由于逻辑与比逻辑或的优先级高,这里将 ② 和 ③ 的结果进行逻辑与运算,即 ++x && ++z。
⑤ 最后将 ④ 的结果与 ① 进行逻辑或运算,即 --y||++x&&++z。
如果没有上述对该表达式执行顺序的说明,第一眼看到它时将很难识别优先级。对于这类问题,可以通过添加小括号使表达的顺序更加清晰,而不用去查优先级表。如下所示为改进后的表达式:
(--y)||((++x)&&(++z));