与C、C++相似,Java中也存在多种运算符,对数据进行处理,且运算符类型跟C、C++有着极大的相似性。比如,用于赋值的赋值运算符、用于运算的算数运算符和自增自减运算符、用于比较的关系运算符,用于逻辑运算的逻辑运算符、用于位运算的位运算符和移位操作符、复合三元操作符等。本篇文章将简单讲述一下Java中各种运算符的使用规则。
1. 赋值运算符
赋值运算符常用于变量赋值运算,最基本的格式为”=”,可以将赋值号右边的表达式结果赋给左边的操作数。Java中共存在如下几种操作符:
运算符 | 名称 | 语义 |
---|---|---|
= | 赋值 | a = b + c,将b+c表达式结果赋值给变量a |
+= | 加等于 | 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 |
注意事项:
- 左右操作数都是变量的赋值运算对于基本类型赋值和对象赋值之间存在差异,简单的讲基本类型赋值,左操作数得到赋值后值的改变不影响右操作数变量,而对于对象赋值,左操作数值的改变会同步影响右操作数变量,这个在讲对象的时候再详细讲一下。
//基本类型赋值 int b = 1; int a = b; a = 2; //之后a的值为2,b的值为1,不影响b的值 //对象类型赋值 Person person1 = new Person("zhuoli", 19, "programmer"); Person person2 = person1; person2.setAge = 20; //之后person1和person2的成员变量age都为20
- 对于复合运算符+=、-=、*=、/=、%=不会改变结果的类型,所以越界时,计算结果会产生异常,比如
byte b = 127; b += 1; //b=-128,因为b通过复合运算符 += 运算后,类型仍为byte,范围为-128~127
2. 算术运算符
Java中的算术运算符用于进行算术运算,基本与数学中的算术运算规则一致。有一点特殊的是,Java中的整数除运算(/),会舍弃小数部分。
运算符 | 名称 | 语义 |
---|---|---|
+ | 加 | 算术加 |
– | 减 | 算术减 |
* | 乘 | 算术乘 |
/ | 除 | 算术除 |
% | 模 | 算术模 |
++ | 自增运算符 | 自增运算 |
— | 自减运算符 | 自减运算 |
对于+、-、*、/、%在进行算术运算时,会根据上节讲的自动类型转换规则进行自动类型转换。这里特别讲一下自增自减运算符,n++将变量n的当前值加1,n–将当前n的值减1。例如:
int n = 12;
n++;
n的值将变为13,因为自增自减运算符改变了变量的值,所以自增自减运算符的操作数不能是数值,比如4++就是一条非法的语句。除了上述后缀形式,自增自减运算符还有一种前缀形式,++n、–n。两中方式都是对变量进行加1,减1操作,但是在表达式中,这两种形式就有区别了。前缀方式先对变量进行加1运算,然后使用加1运算后的值参与后续运算,后缀方式先使用变量原来的值进行运算,然后再对变量进行加1运算。
int m = 7;
int n = 7;
int a = 2 * ++m; //now a is 16, m is 8
int b = 2 * n++; //now a is 14, n is 8
建议不要再表达式中使用++、–,这样的代码容易使人困惑,并产生一些不易发现的bug。
3. 关系运算符
关系运算符就是用来比较两个表达式关系的运算符,包括一下几种:
运算符 | 名称 | 语义 |
---|---|---|
> | 大于 | 大于 |
< | 小于 | 小于 |
>= | 大于等于 | 大于或等于 |
<= | 小于等于 | 小于或等于 |
== | 等于 | 等于 |
!= | 不等于 | 不等于 |
对于>、<、>=、<=这集中关系运算符,都比较简单,跟数学中的语义一致,可以用于比较基本类型数值类型(非boolean)数据及其包装类型(对象)的关系,都是用于比较数值的大小关系。但是对于==和!=对于基本类型和包装类型(对象)的运算有着很大的区别。简单的讲,对于基本类型,==和!=关系运算符比较的是左右操作数的数值;而对于包装类型,==和!=关系运算符比较的是左右操作符对象的地址,此外对于基本类型包装类型及String类型,再使用==和!=关系运算符时,还要将运行时常量池的因素考虑在内,这个后续会再相应的文章中说明,本节不进行重点介绍。如果想比较对象的内容而非地址,可以使用对象的equals方法,对于自定义对象,注意覆盖equals方法,否则比较的仍是对象的地址。
4. 逻辑运算符
逻辑运算符用于连接多个布尔型表达式,计算逻辑结果,主要存在以下几种形式:
运算符 | 名称 | 语义 |
---|---|---|
&& | 逻辑与 | 当且仅当两个操作数都为真,结果才为真 |
|| | 逻辑或 | 任何两个操作数任何一个为真,结果为真 |
! | 逻辑非 | 反转操作数的逻辑状态,条件为true,则逻辑非运算符将得到false |
& | 逻辑与 | 当且仅当两个操作数都为真,结果才为真,与&&不同的是,&是非短路的 |
| | 逻辑或 | 任何两个操作数任何一个为真,结果为真,与||不同的是,|是非短路的 |
这里讲一下短路和非短路的区别:&&和||都是按照短路的方式求值的,如果第一个操作数已经能够确定表达式对的结果,那第二个操作数就不必计算了。比如:expression1 && expression2,并且第一个表达式的值为false,结果不可能为真。因此,第二个表达式的值就没必要计算了。但是&和|是非短路的,无论第一个表达式能否确定表达式的结果,第二个表达式都会计算。比如
// x ==0
x != 0 && x++ == 0 //结果为false,x的值为0,因为短路,x++并没有进行计算
x != 0 & x++ == 0 //结果为false,x的值为1,因为是非短路的,第二个表达式也进行了计算
5. 位运算符
再处理整型数值时,可以直接对组成整型数值的各个位(二进制位)进行操作,开发中使用的不是很多,主要存在以下几种形式:
运算符 | 名称 | 语义 |
---|---|---|
& | 按位与 | 相对应位都是1,则结果为1,否则为0 |
| | 按位或 | 相对应位都是0,则结果为0,否则为1 |
^ | 按位异或 | 相对应位值相同,则结果为0,否则为1 |
~ | 按位非 | 按位取反运算符翻转操作数的每一位,即0变成1,1变成0 |
<< | 按位左移 | 左操作数按位左移右操作数指定的位数 |
>> | 按位右移 | 左操作数按位右移右操作数指定的位数,用符号位填充高位 |
>>> | 按位右移补零 | 左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充 |
这里可以看出,&和|除了用作逻辑运算符之外,还可以用作位运算符,区别在于操作数是否为布尔型表达式。
6. 三元操作符
Java同C和C++一样,支持三元操作符?:,表达式格式为
condition ? expression1 : expression2;
当condition为真时,三元表达式的结果为expression1的值,否则结果为expression2的值。