本文最后更新于:2024年3月18日 凌晨
Java 表达式与运算符
- 表达式是由操作数和运算符按一定的语法形式组成的式子,一个常量或一个变量可以看作表达式的特例,其值即该常量或变量的值在表达式中,表示各种不同运算的符号称为运算符,参与运算的数据称为操作数。
- 组成表达式的运算符有很多种,按操作数的数目来分,有如下3种:
一元运算符
- 只需要一个运算对象的运算符称为一元运算符,例如,++,–,+,-等,如:
一元运算符支持前缀或者后缀记号
二元运算符
- 需要两个运算对象额运算符号称为二元运算符,例如赋值号"=",可以看作是一个二元运算符,它指将右边的运算对象赋给左边的运算对象,其他二元运算符有+, -, *, /, <, >等,例如:
- 所有的二元运算符使用中缀记号,及运算符出现在两个运算对象中间。
三元运算符
- 三元运算符需要3个运算对象,Java有一个三元运算符"?:",它是一个简单的if…else语句。
- 三元运算符也使用中缀记号,例如:
- 运算除了执行一个操作,还返回一个数值。返回数值和它的类型取决于运算符号和运算对象的类型,例如,算术运算符完成基本的算数操作(如加,减)并且返回数值作为算数操作的结果。由算术运算符返回的数据类型取决与它的运算对象的类型。如果两个整型数相加,结果就是一个整形数;如果量的实型数相加,那么将结果为实型数。
- 可以将运算符分为算术运算符,关系运算符,逻辑运算符,位运算符,赋值组合运算符和其他运算符。
算数运算符
算术运算是针对数值类型操作数进行的运算,根据需要参与运算的操作数的数目要求,可将算术运算符分为双目运算符和单目运算符两种。
双目算术运算符
运算符 |
使用形式 |
描述 |
举例 |
结果 |
+ |
op1+op2 |
op1加上op2 |
5+6 |
11 |
- |
op1-op2 |
op1减去op2 |
6.2-2 |
4.2 |
* |
op1*op2 |
op1乘以op2 |
3*4 |
12 |
/ |
op1/op2 |
op1除以op2 |
7/2 |
3 |
% |
op1%op2 |
op1除以op2的余数 |
9%2 |
1 |
注意
- "/"运算对整数和浮点数的情况不同,7/2结果为3. ,而7.0/2.0结果为3.5,也就是说整数相除将舍去小数部分。而浮点数相除则要保留小数部分。
- 取模运算"%"一般用于整数运算,它用来得到余数部分。例如,7%4的结果为3,但参与运算的值为负数时,结果的正负性取决于被除数的正负。
- 如果出现各种类型数据的混合运算,系统将按自动转换原则将操作数转换为同一类型,再进行运算。如一个整数和一个浮点数进行计算,结果为浮点型。
单目算术运算符
运算符 |
使用形式 |
描述 |
功能等价 |
++ |
a或a |
自增 |
a=a+1 |
- - |
a- -或- -a |
自减 |
a=a-1 |
- |
-a |
求相反数 |
a=-a |
- 变量的自增与自减与和- -出现在该变量前后位置无关,无论是x还是x++均表示x要增1
- 表达式的值与运算符的位置有关。例如,x=2,则(x)结果为9,也就是x的返回值时3;而(x3)结果为6,即x的返回值为2,如果是变量打头,则取变量在递增前的值作为表达式结果,实际就是变量原有值;如果是++打头,则强调要取"加后:的结果,也即取变量递增后的值作为表达式结果。
关系运算符
关系运算符也称比较运算符,用于比较两个数据之间的大小关系,如下表所示,关系运算结果是布尔值(true或false),如果x的值为5,则x>3的结果为true
运算符 |
用法 |
描述 |
举例 |
> |
op1>op2 |
op1大于op2 |
x>3 |
>= |
op1>=op2 |
op1大于等于op2 |
x>=4 |
< |
op1<op2 |
op1小于op2 |
x<3 |
<= |
op1<=op2 |
op1小于等于op2 |
x<=4 |
== |
op1==op2 |
op1等于op2 |
x==2 |
!= |
op1!=op2 |
op1不等于op2 |
x!=1 |
逻辑运算符
- 逻辑运算是针对布尔型数据进行的计算,运算的结果仍然是布尔型,常用的逻辑运算有与(AND),或(OR),非(NOT),如下表所示:
逻辑运算 |
含义 |
A AND B |
A,B均为真时结果才为真 |
A OR B |
A,B中有一个为真时结果就为真 |
NOT A |
结果为A的相反值 |
运算符 |
用法 |
何时结果为true |
附加特点 |
&& |
op1&&op2 |
op1和op2都是true |
op1为false时,不计算op2 |
|| |
op1||op2 |
op1或op2是true |
op1为true时,不计算op2 |
! |
!op |
op为false |
|
- 从上表可以看出,计算逻辑表达式时,在某些情况下,不必要对整个表达式的各部分进行计算。例如,
(5==2)&&(2<3)
的结果为false.实际只用计算5==2
的值,发现其为false,则判定整个逻辑表达式的结果为false,右边的(2<3)没被计算。在一些特殊情况下,右边的表达式也许会产生某个异常情形,但却因为没有执行右边的计算而没有表现出来。对于或逻辑,在左边的运算为真时也不执行右边的运算。
- 例如,设x=3,执行下面语句结果为true:
1
| System.out.println((x==3)||(x/0>2));
|
1
| System.out.println((x/0>2)||(x==3));
|
位运算符
- 位运算是对操作数以二进制比特(bit)位为单位进行的操作运算,位运算的操作数和结果都是整型数,几种位运算符和相应的运算规则如下表所示:
运算符 |
用法 |
操作 |
~ |
~op |
结果时op按比特位求反 |
>> |
op1>>op2 |
将op1右移op2个位(带符号) |
<< |
op1<<op2 |
将op1左移op2个位(带符号) |
>>> |
op1>>>op2 |
将op1右移op2个位(不带符号的右移) |
& |
op1&op2 |
op1和op2都是true,结果才为true |
| |
op1|op2 |
op1或op2有一个是true,则结果为true |
^ |
op1^op1 |
op1和op2异或 |
注意
- 对于
&
和|
运算符,参与运算的两个运算量可以是逻辑值,也可以是数值数据,对于数值数据,将对两运算量按位对应计算,这时,1相当于true,0相当于false,这个位运算符没有前面逻辑运算符的附加特点
- 二进制数用补码存储:先补全8位,将原码的每一位求反再加一得到补码。
&和&&的区别?
- &运算符有两种用法:按位与和逻辑与。
- &&运算符是短路与运算,逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是true整个表达式的值才是true,&&之所以称为短路运算是因为,如果&&左边的表达式的值是false,右边的表达式会被直接短路掉,不会进行运算。
- 很多时候我们可能都需要用&&而不是&,例如在验证用户登录时判定用户名不是null而且不是空字符串,应当写为:
username != null &&!username.equals("")
,二者的顺序不能交换,更不能用&运算符,因为第一个条件如果不成立,根本不能进行字符串的equals比较,否则会产生NullPointerException异常。
- 注意:逻辑或运算符(|)和短路或运算符(||)的差别也是如此
移位运算符
- 移位运算符是将某一变量所包含的各比特位按指定方向移动指定的位数,移位运算符通过对第一个运算对象左移或者右移位来对数据执行位操作,移动的位数由右边的操作数决定,移位的方向取决于预算符本身,下表给出移位运算符使用的具体例子。
x(十进制表示) |
x的二进制补码表示 |
x<<2 |
x>>2 |
x>>>2 |
30 |
00011110 |
01111000 |
00000111 |
00000111 |
-17 |
11101111 |
10111100 |
11111011 |
00111011 |
- 从上表可以看出,数据在计算机内部是以二进制补码的形式存储的,正负数的区别看最高位,最高位为0则数据是正数,为1则数据是负数。显然,对数据的移位操作不能改变数据的正负性质,因此,在处理带符号的右移中,右移后左边留出的空位上复制的是原码的符号位。而不带符号的右移中,右移后左边的空位一律填0.带符号的左移在后边填补0
按位逻辑运算符
- 位运算符
&
,|
,~
,^
分别提供了基于位的与(AND),或(OR),求反(NOT),异或(XOR)操作,其中异或~
是指两位值不同时,对应的结果位为1,否则为0
- 不妨用两个数进行计算,例如,
x=13
,y=43
,计算各运算结果。
- 首先,将数据转换为二进制形式:
x=1101
,y=101011
,考虑到数据在计算机内的存储表示,不妨以字节数据为例,x和y占用一个字节,所以x和y的二进制为:x=00001101
,y=00101011
~x
结果应为11110010,十进制结果为-14
- 14的二进制为1110,补全8位即00001110,-14的补码是14的原码求反加1,即
11110001+1=11110010
x&y=1001
,即十进制的9
1 2 3 4
| 00001101 & 00101011 ------------ 00001001
|
赋值组合运算符
- 赋值组合运算符是指在赋值运算符的左边有一个其他运算符,例如。
- 其功能是先将左边变量与右边的表达式进行某种运算后,再把运算的结果赋给变量能与赋值符结合的运算符包括算数运算符(
+
,-
,*
,/
,&
),位运算符(&
,|
,^
)和位移运算符(>>
,<<
,>>>
)
其他运算符
下表给出了其他运算符的简要说明,这些运算符的具体应用将在以后用到。
运算符 |
描述 |
?: |
作用相当于if…else语句 |
[] |
用于声明数据,创建数组以及访问数组元素 |
. |
用于访问对象或者类的成员 |
(type) |
强制类型转换 |
new |
创建一个新的对象或者新的数组 |
instanceof |
判断对象是否为类的实例 |
说明
- 其含义是如果条件的计算结果位真,则结果为表达式1的计算结果,否则为表达式2的计算结果,利用以下语句可以求两个数a,b的最大值:
instanceof
用来决定第一个运算对象是否为第二个运算对象的一个实例,例如:
1 2 3
| String x="hello World!"; if(x > instanceif String) System,out.println("x is a instance of String:");
|
运算符优先级
- 运算符的优先级决定了表达式中不同运算执行的先后顺序,例如,在算术表达式中,
*
号额优先级高于+
号,所以5+3\*4
相当于5+(3*4)
;在逻辑表达式中,关系运算符的优先级高于逻辑运算符,所以x>y&&x<5
相当于(x>y)&&(x<5)
- 在运算符优先级相同时,运算的进行次序取决于运算符的结合性,例如,
4*7%3
应理解为(4\*7)%3
,结果为1,而不是4*(7%3)
,结果为4
- 运算符的结合性分为左结合和右结合,左结合就是按由左向右的次序计算表达式,例如上面的
4*7%3
,而右结合就是按右到左的次序计算,例如,a=b=c
相当于a=(b=c)
,再如,a?b:c?d:e
相当于a?b:(c?d:e)
,Java运算符的优先级与结合表如下表所示:
运算符 |
描述 |
优先级 |
综合性 |
( ) |
圆括号 |
15 |
左 |
new |
创建对象 |
15 |
左 |
[ ] |
数组下标运算 |
15 |
左 |
. |
访问成员(属性/方法) |
15 |
左 |
++,– |
后缀自增/自减1 |
14 |
右 |
++,– |
前缀自增/自减1 |
13 |
右 |
~ |
按位取反 |
13 |
右 |
! |
逻辑非 |
13 |
右 |
-,+ |
算术符号(负号/正号) |
13 |
右 |
(type) |
强制类型转换 |
13 |
右 |
*,/,% |
乘/除/取模 |
12 |
左 |
+,- |
加/减 |
11 |
左 |
<<,>>,>>> |
移位 |
10 |
左 |
<,>,<=,>=,instanceof |
关系运算 |
9 |
左 |
==,!= |
相等性运算 |
8 |
左 |
& |
位逻辑与 |
7 |
左 |
^ |
位逻辑异或 |
6 |
左 |
| |
为逻辑或 |
5 |
左 |
&& |
逻辑与 |
4 |
左 |
|| |
逻辑或 |
3 |
左 |
?: |
条件运算符 |
2 |
右 |
=,+=,-=,*=,/=,%=&=,^=,|=,<<=,>>=,>>>= |
赋值运算符 |
1 |
右 |