Java 中的运算符
运算符的分类如下:
- 算术运算符
- 关系运算符
- 位运算符
- 逻辑运算符
- 赋值运算符
- 其他运算符
一、算数运算符
算术运算符用在数学表达式中,它们的作用和在数学中的作用一样。下表列出了所有的算术运算符:
+
-
*
/
%
++
--
1、自增自减运算符
1 | public class selfAddMinus{ |
运行结果为:
1 | 进行自增运算后的值等于4 |
解析:
int b = ++a;
拆分运算过程为: a=a+1=4; b=a=4;
, 最后结果为 b=4,a=4
int d = --c;
拆分运算过程为: c=c-1=2; d=c=2;
, 最后结果为 d=2,c=2
- 前缀自增自减法(
++a
,--a
):先进行自增或者自减运算,再进行表达式运算 - 后缀自增自减法(
a++
,a--
):先进行表达式运算,再对a本身进行自增或者自减运算
下面是一些例子:
1 | public class selfAddMinus{ |
运行结果为:
1 | 自增运算符前缀运算后a=6,x=12 |
1 | public class PlusPlus { |
运算结果为:
1 | 5 |
二、关系运算符
==
!=
>
<
>=
<=
等于和不等于适用于所有的基本数据类型,而其他比较符不适用于 boolean
类型,因为 boolean
值只能是 true 或 false,“大于”和“小于”没有实际意义
三、位运算符
1、按位操作符
按位操作符用来操作整数基本数据类型中的单个 bit,即二进制位。按位操作符会对两个参数中对应的位执行布尔代数运算,并最终生成一个结果。
按位操作符来源于C语言面向底层的操作,在这种操作中经常需要直接操纵硬件,设置硬件寄存器内的二进制位。
Java 定义了位运算符,应用于整数类型 int
,长整型 long
,短整型 short
,字符型 char
和字节型 byte
等类型。
符号 | 类型 | 描述 |
---|---|---|
& |
按位与 | 如果相对应位都是1,则结果为1,否则为0 |
| | 按位或 | 如果相对应位都是0,则结果为0,否则为1 |
^ |
按位异或 | 如果相对应位值相同,则结果为0,否则为1 |
~ |
按位非 | 按位补运算符翻转操作数的每一位,即0变成1,1变成0 |
- 除了
~
,按位操作符都可与等号联合使用,以便合并运算和赋值 - 布尔值被作为一种单比特值对待,可以对它进行按位与、或、异或,但是不能执行按位非(可能是为了避免与逻辑非混淆)
- 对于布尔值,按位操作符具有与逻辑操作符相同的效果,只是不会短路
例子如下:
1 | int a = 0b0011_1100; |
2、移位操作符
移位操作符的运算对象也是二进制的位,移位操作符只可以用来处理整数类型。
符号 | 类型 | 描述 |
---|---|---|
<< |
按位左移运算符 | 左操作数按位左移右操作数指定的位数,并在低位补零 |
>> |
按位右移运算符 | 左操作数按位右移右操作数指定的位数,如果左操作数符号为正,则在高位插入0,如果符号为负,则在高位插入1 |
>>> |
按位右移补零操作符 | 左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。 |
- 如果对
char
、byte
或short
类型的数值进行移位处理,那么在移位进行之前,他们会被转换为int
类型,并且得到的结果也是一个int
类型的值。 - 移位操作符也可以与等号联合使用,但是无符号右移位结合赋值操作可能会出现问题:如果对
byte
或short
值进行移位运算,得到的可能不是正确的结果
示例如下:
1 | A = 0011 1100 |
四、逻辑运算符
&&
,逻辑与||
,逻辑或!
,逻辑非
这三个操作符能根据参数的逻辑关系生成一个布尔值,并且只能适用于布尔值,与 C 及 C++ 中不同的是不可将一个非布尔值当做布尔值在逻辑表达式中使用。
1、短路
当使用逻辑运算符时,会遇到一种短路的现象,即一旦能够明确无误地确定整个表达式的值,就不再计算表达式余下的部分了,因此整个逻辑表达式靠后的部分有可能不会被运算。示例如下:
1 | int a = 1; |
上面的例子中,第一个判断中 a==c
为false,运算符为 &&
则后面的表达式没有进行判断的必要了;同样第二个判断中后面的表达式也没有判断的必要了,如果进行判断只是单纯地浪费而已。
2、&&
与 ||
的优先级
&&
的优先级大于 ||
,下面这段代码可以证明:
1 | boolean a = 2 == 2 || 3 == 1 && 2 == 5; |
a 的值为 true,如果从左向右依次判断的话,为 false;因为 &&
优先级高于 ||
,所以会先执行 &&
运算符的运算。
五、赋值运算符
=
+=
-=
*=
/=
(%)=
,取模和赋值操作符,它把左操作数和右操作数取模后赋值给左操作数<<=
,左移位赋值运算符>>=
,右移位赋值运算符&=
,按位与赋值运算符^=
,按位异或赋值操作符|=
,按位或赋值操作符
六、其他运算符
1、三元操作符 if-else
C语言发明了该操作符。
对 ?
之前的表达式进行判断,如果为 true,返回 :
之前的内容,如果为 false,返回 :
之后的内容
1 | String resolve(){ |
2、字符串操作符 +
和 +=
+
除了做加法操作之外,还有一个特殊的用途:连接字符串。
C++ 中具有操作符重载的机制,以便程序员可以为几乎所有的操作符增加功能,但与 C++ 的另外一些限制结合在一起,使得操作符重载称为一种非常复杂的特性。Java 中没有该机制
- 如果表达式以一个字符串开头,那么后续所有的操作数都必须是字符串型
- 如果在连接字符串之前有
+
作用域数值类型,则前面的加法运算不受影响
1 | int a = 1, b = 2, c = 3; |
输出结果为:
1 | 6hhh |
3、类型转换操作符
类型转换的原意为“模型铸造”,在适当的时候,Java 会将一种数据类型自动转换成另一种。例如,假设为某浮点变量赋值一个整数值,编译器会自动将 int 转换为 float。
在 C 和 C++ 中,类型转换有时会让人很头疼。但是在 Java 中,类型转换是一种比较安全的操作。
- 窄化转换,将能容纳更多信息的数据类型转换成无法容纳那么多信息的类型,就有可能面临信息丢失的危险,此时编译器会强制我们进行类型转换。
- 扩展转换,则不必要显式地进行类型转换,因为新类型肯定能容纳原来类型的信息,不会造成任何信息的丢失。
Java 允许我们把任何基本数据类型转换成别的基本数据类型,但是布尔型除外,布尔型不允许进行任何类型的转换处理
4、截尾和舍入
在执行窄化转化时,必须注意截尾和舍入的问题。
1 | double a = 0.7; |
输出结果为:
1 | 0 |
将浮点型转换为 int 类型,会对该数字进行截尾。如果想要得到舍入的结果,需要使用 java.lang.Math
中的 round
方法
5、提升
表达式中出现了好几种数据类型,出现的最大的数据类型决定了表达式最终结果的数据类型。
例如,对基本数据类型执行算数运算或按位运算,只要类型比 int 小的在运算之前,这些值会自动转换成 int
6、Java 中没有 sizeof
在 C 和 C++ 中,sizeof()
操作符可以告诉你为数据项分配的字节数,需要使用该操作符最大的原因是不同的数据类型在不同的机器上可能有不同的大小,所以进行一些与存储空间有关的运算时,程序员必须要知道这些数据类型有多大。Java 中就不存在这种问题,所有的数据类型在所有的机器中的大小都是相同的,因为程序运行在 Java 虚拟机上。
七、运算符的优先级
优先级 | 运算符 | 描述 | 结合性 |
---|---|---|---|
1 | [] , () , . , :: |
数组下标、方法调用、成员访问、方法引用 | 左结合 |
2 | ++ , -- , + , - , ~ , ! , (type) , new |
前缀自增/自减、正负号、按位取反、逻辑非、类型转换、对象创建 | 右结合 |
3 | * , / , % |
乘法、除法、取模 | 左结合 |
4 | + , - |
加法、减法/字符串连接 | 左结合 |
5 | << , >> , >>> |
左移、带符号右移、无符号右移 | 左结合 |
6 | < , <= , > , >= , instanceof |
小于、小于等于、大于、大于等于、类型比较 | 左结合 |
7 | == , != |
等于、不等于 | 左结合 |
8 | & |
按位与 | 左结合 |
9 | ^ |
按位异或 | 左结合 |
10 | | | 按位或 | 左结合 |
11 | && |
逻辑与 | 左结合 |
12 | || | 逻辑或 | 左结合 |
13 | ? : |
三元运算符 | 右结合 |
14 | = , += , -= , *= , /= , %= , <<= , >>= , >>>= , &= , ^= , |= |
赋值及复合赋值运算符 | 右结合 |
15 | , |
逗号运算符 | 左结合 |
结合性:指当多个相同优先级的运算符出现在表达式中时,运算符的执行顺序。
- 左结合:从左到右依次执行。
- 右结合:从右到左依次执行。
相关链接
OB links
OB tags
#Java