- 算术运算符:+, -,*,/,%,++,--
- 关系运算符:==,!=,<,>,<=,>=
- 逻辑运算符:&&,||,!,&,|,^
- 位运算符:&,|,~,^
- 移位运算符:<<, >>, >>>
- 赋值运算符:=,+=,-=,*=,/=,%=,&=,!=,^=,>>=,<<=,>>>=
- 条件运算符:表达式1 ? 表达式2:表达式3
- 其他运算符:[ ],.,(),(type),new,instanceof
1.算术运算符
1.1.二元算术运算符(基本五则运算符):+, -,*,/,%
注:
1).int/int结果还是int,/需要用double来计算;
2).0不能作为除数;
3).%表示取余,不仅可以对int求模,也能对double求模;
1.2.一元算术运算符:+,-,(自增/自减运算符):++,--
运算符 | 用法 | 功能描述 |
+ | +op | 如果op是byte,short或char类型,则将op类型提升为int型 |
- | -op | 取op的负值 |
int a = 10;
int b = ++a; //先+1后赋值
System.out.println(b); //b = 11, a = 11
int c = a++; //先赋值后+1
System.out.println(c); //c = 10, a = 11
注:
1).如果不取自增运算的表达式的返回值,则前置自增和后置自增没有区别;
2).如果取表达式的返回值,则前置自增的返回值是自增之后的值,后置自增的返回值是自增之前的值。
3).Java中没有幂运算符,必须采用Java.lang.Math类的pow()方法:
public static double pow(double a, double b); //返回值是a的b次方
Java.lang.Math类提供了大量数学和工程函数。
例如:Π和e均由常数表示,且为双精度类型,非常准确。
Math类包含数学函数:平方根,自然对数,乘幂,三角函数等;
也包含一些基本函数:如可对浮点数进行四舍五入运算,计算同样类型两个数字的最大和最小值,计算绝对值等。
2.关系运算符:==,!=,<,>,<=,>=
int a = 10;
int b = 20;
System.out.println(a == b);
System.out.println(a != b);
System.out.println(a < b);
System.out.println(a > b);
System.out.println(a <= b);
System.out.println(a >= b);
注:
1).关系运算符的表达式返回值都是boolean类型。
2).Java中,任何类型的数据(包括基本数据类型和复合类型)都可以通过==或!=来比较是否相等(这与C和C++不同)。
3.逻辑运算符:&&,||,!,&,|,^
注:逻辑运算符的操作数(操作数往往是关系运算符的结果)和返回值都是boolean。
3.1.逻辑与&&
规则:两个操作数都为true,结果为true,否则结果为false.
int a = 10;
int b = 20;
int c = 30;
System.out.println(a < b && b < c);
3.2.逻辑或||
规则:两个操作数都为false,结果为false,否则结果为true.
int a = 10;
int b = 20;
int c = 30;
System.out.println(a < b || b < c);
3.3.逻辑非!
规则:操作数为true,结果为false;操作数为false,结果为true(这是个单目运算符,只有一个操作数)
int a = 10;
int b = 20;
System.out.println(!a < b);
短路求值
&&和||遵守短路求值规则。
System.out.println(10 > 20 && 10 / 0 == 0); //打印false
System.out.println(10 < 20 || 10 / 0 == 0); //打印true
//计算10/0会导致程序抛出异常,但是上面的代码却能正常运行,说明10/0并没有正常被求值
结论:
1).对于&&,如果左侧表达式值为false,则表达式整体的值一定是false,无需计算右侧表达式;
2).对于||,如果左侧表达式值为true,则表达式整体的值一定是true,无需计算右侧表达式。
3.4&3.5. 不短路与或运算 & 和 |(不推荐使用)
& 和 | 如果操作数为boolean的时候,也表示逻辑运算,但是和&& 以及 || 相比,它们不支持短路求值。
System.out.println(10 > 20 & 10 / 0 == 0); //程序抛出异常
System.out.println(10 < 20 | 10 / 0 == 0); //程序抛出异常
3.6. ^
op1^op2:op1和op2值不同,即一个取true,另一个取false时,返回true。
4.位运算符:&,|,~,^
Java中对数据的操作的最小单位不是字节,而是二进制位。
位操作表示按二进制位运算,计算机中都是使用二进制来表示数据的(01构成的序列),按位运算就是按照二进制位的每一位依次进行计算。
4.1.按位与&:如果两个二进制位都是1,则结果为1,否则结果为0
int a = 10;
int b = 20;
System.out.println(a & b);
进行按位运算,首先要把10和20转成二进制,分别为1010和10100.
10 -> 01010
20 -> 10100
结果 -> 00000 转换为十进制为0
4.2.按位或|:如果两个二进制位都是0,则结果为0,否则结果为1
int a = 10;
int b = 20;
System.out.println(a | b);
运算方式和按位与类似。
4.3.按位取反~:如果该位为0则转为1,如果该位为1则转为0
public class Test {
public static void main(String[] args) {
int a = 0xf;
System.out.printf("%x\n", ~a);
System.out.println(~a);
}
}
注:
1).0x 前缀的数字为十六进制数字,十六进制可以看成是二进制的简化表示方式。一个十六进制数字对应 4 个二进制位。
2).0xf 表示 10 进制的 15, 也就是二进制的 1111。
3).printf 能够格式化输出内容, %x 表示按照十六进制输出。
4).\n 表示换行符
4.4.按位异或 ^: 如果两个数字的二进制位相同, 则结果为0, 相异则结果为1
int a = 0x1;
int b = 0x2;
System.out.printf("%x\n", a ^ b);
经典问题:一个数组中只有一个数出现一次,其他数都出现两次,请找到这个数。
注:
当 &,|和^ 的操作数为整数(byte,short,int,long)时,表示按位运算,当操作数为boolean时,表示逻辑运算。
5.移位运算符:<<, >>, >>>
算术左移操作符:<<
算术右移操作符:>>
逻辑右移操作符:>>>
Java使用补码来表示二进制数。因此移位运算都是针对整型数的二进制补码进行。在补码表示中,最高位为符号位,正数的符号位为0,负数为1。补码的规定如下:
1).对正数来说,最高位为0,其余各位代表数值本身(以二进制表示),如+42的补码为00101010。
2).对负数来说,把该数绝对值的补码按位取反,然后对整个数加1,即得该数的补码。如-1的补码为11111111(-1绝对值的补码为00000001,按位取反再加1为11111110+1=11111111)。用补码来表示数,0的补码是唯一的,为00000000。
运算符 | 用法 | 操作描述 |
<< | op1<<op2 | 将op1向左移动op2个位 |
>> | op1>>op2 | 将op1向右移动op2个位 |
>>> | op1>>>op2 | 将op1向右移动op2个位(无符号) |
5.1.左移 <<: 最左侧位不要了, 最右侧补 0.
int a = 0x10;
System.out.printf("%x\n", a << 1);
// 运行结果(注意, 是按十六进制打印的)
20
十六进制数转换为二进制数:将十六进制数的每一位转换为4位二进制数,组合。
0x10 -> 0001 0000
左移 -> 0010 0000
结果 -> 2 0
5.2.右移 >>: 最右侧位不要了, 最左侧补符号位(正数补0, 负数补1)
int a = 0x10;
System.out.printf("%x\n", a >> 1);
// 运行结果(注意, 是按十六进制打印的)
8
int b = 0xffff0000;
System.out.printf("%x\n", b >> 1);
// 运行结果(注意, 是按十六进制打印的)
ffff8000
0x10 -> 0001 0000
右移 -> 0000 1000
结果 -> 0 8
0xffff0000 -> 1111 1111 1111 1111 0000 0000 0000 0000
右移 -> 1111 1111 1111 1111 1000 0000 0000 0000
结果 -> f f f f 8 0 0 0
5.3.无符号右移 >>>: 最右侧位不要了, 最左侧补 0
int a = 0xffffffff;
System.out.printf("%x\n", a >>> 1);
// 运行结果(注意, 是按十六进制打印的)
7fffffff
0xffffffff -> 1111 1111 1111 1111 1111 1111 1111 1111
无符号右移 -> 0111 1111 1111 1111 1111 1111 1111 1111
结果 -> 7 f f f f f f f
注:
1). 左移 1 位,相当于原数字 * 2,左移 N 位, 相当于原数字 * 2 的N次方。
2). 右移 1 位,相当于原数字 / 2,右移 N 位,相当于原数字 / 2 的N次方。
3). 由于计算机计算移位效率高于计算乘除,当某个代码正好乘除 2 的N次方的时候可以用移位运算代替。
4). 移动负数位或者移位位数过大都没有意义。
6.赋值运算符:赋值运算符和扩展赋值运算符
6.1.赋值运算符:"="
6.2.扩展赋值运算符:在"="前加上其他运算符
+=:a += 3 等价于 a = a + 3
-=,*=,/=,%=,&=,!=,^=,>>=,<<=,>>>=
7.条件运算符:表达式1 ? 表达式2:表达式3
当表达式1的值为true时,整个表达式的值为表达式2的值;当表达式1的值为false时,整个表达式的值为表达式3的值。
也是Java中唯一的一个三目运算符,是条件判断语句的简化写法。
// 求两个整数的最大值
int a = 10;
int b = 20;
int max = a > b ? a : b;
8.其他运算符:[ ],.,(),(type),new,instanceof
运算符 | 格式 | 操作描述 |
[ ] | type[ ] | 声明类型为type的数组 |
[ ] | type[op1] | 创建op1个元素的数组 |
[ ] | op1[op2] | 访问op1数组的索引为op2的元素 |
. | op1.op2 | 引用op1对象的成员op2 |
( ) | op1(params) | 方法调用 |
(type) | (type)op1 | 将op1强制类型转换为type类型 |
new | new op1 | 创建对象或数组。op1可以是构造方法的调用,也可以是数组的类型和长度 |
instanceof | op1 instanceof op2 | 如果op1是op2的实例,则返回true |
9.运算符的优先级
运算符之间是有优先级的。具体的规则我们不必记忆。在可能存在歧义的代码中加上括号即可。
优先级顺序 | 运算符类别 | 运算符 |
1 | 后缀运算符 | [ ],.,(params)expr++,expr-- |
2 | 一元运算符 | ++expr,--expr,+expr,-expr,~,! |
3 | 创建或强制类型转换 | new(type)expr |
4 | 乘,除,求余 | *,/,% |
5 | 加,减 | +,- |
6 | 移位 | <<,>>,>>> |
7 | 关系运算 | <,>,<=,>=,instanceof |
8 | 相等性判定 | ==,!= |
9 | 按位与 | & |
10 | 按位异或 | ^ |
11 | 按位或 | | |
12 | 逻辑与 | && |
13 | 逻辑或 | || |
14 | 条件运算 | ?: |
15 | 赋值 | =,+=,-=,*=,/=,%=,&=,!=,^=,>>=,<<=,>>>= |