Java运算符
- 算术运算符
- 关系运算符
- 位运算符
- 逻辑运算符
- 赋值运算符
- 三元运算符(条件运算符)
- 其他运算符
- 运算符优先级
- 常见问题与技巧
算术运算符
用于数值计算,适用于整数和浮点数。
运算符 | 描述 | 示例 | 注意点 |
---|---|---|---|
+ | 加法 | 3 + 2 → 5 | 字符串连接时作为拼接符 |
- | 减法 | 5 - 3 → 2 | |
* | 乘法 | 3 * 4 → 12 | |
/ | 除法 | 10 / 3 → 3 | 整数除法会截断小数部分 |
% | 取模(余数) | 10 % 3 → 1 | 结果符号与被除数一致 |
++ | 自增 | a++ (后增) | 独立使用时a++ 与++a 等效 |
-- | 自减 | --b (前减) | 复合语句中影响运算顺序 |
示例代码:
// 独立使用时`a++`与`++a`等效 都是原值+1int a = 5;a++;System.out.println(a);//6++a;System.out.println(a);//7int a = 5;int b = a++; // b=5, a=6(后增)int c = ++a; // a=7, c=7(前增)System.out.println(7/3); // 2System.out.println(7%3); // 1
额外注意下浮点型的小数计算保留
double d = 10 / 3; // d=3.0(整数除法)double f = 10 % 3; // f=1.0(取余)double e = 10.0 / 3; // e = 3.3333333333333335double h = 10.0 % 3; // h=1.0
如结果类型是double,会自动进行类型转换,将结果转换为double类型
①如果两个操作数都是整数类型,那么结果也会是整数类型,即只会保留整数部分
②其中一个操作数是double类型时,结果就会是double类型,即会保留小数部分
关系运算符
比较两个值的关系,返回布尔值(true
/false
)。
运算符 | 描述 | 示例 |
---|---|---|
== | 等于 | 5 == 5 → true |
!= | 不等于 | 5 != 3 → true |
> | 大于 | 5 > 3 → true |
< | 小于 | 5 < 3 → false |
>= | 大于等于 | 5 >= 5 → true |
<= | 小于等于 | 5 <= 3 → false |
位运算符
直接操作二进制位,参与运算的数均以补码出现,适用于整数类型
&:按位与
:只有对应的两个二进位都为1时,结果位才为1
int a = 11;// 11 简化补码:00001011int b = 5; // 5 简化补码:00000101System.out.println(a & b);//结果1
11 补码:0000 1011
5 补码:0000 0101
& 结果:0000 0001:换算结果原码真值为 1
|: 按位或
:对应的两个二进位有1个为1时,结果位就为1
int a = 11;// 11 简化补码:00001011int b = 5; // 5 简化补码:00000101System.out.println(a | b);//结果15
11 补码:0000 1011
5 补码:0000 0101
| 结果:0000 1111:换算结果原码真值为 15
^:按位异或
:参加运算的两个对象,按二进制位进行“异或”运算,意思就是两个数对应的二进制位一样^ 计算结果为0,不一样^ 计算结果为1
int a = 11;// 11 简化补码:00001011int b = 5; // 5 简化补码:00000101System.out.println(a ^ b);//结果14
^运算规则:0 ^ 0 = 0; 0 ^ 1 = 1; 1 ^ 0 = 1; 1 ^ 1 = 0;
11 补码:0000 1011
5 补码:0000 0101
^ 结果:0000 1110:换算结果原码真值为 14
~:按位取反
:对参与运算的对象,按照二进制位进行"取反"操作,将每一位的0变为1,1变为0
int a = 11;// 11 简化补码:00001011System.out.println( ~ a);// -12
11 补码:0000 1011
~11结果:1111 0100
首位为1代表负,先尾减1得反码1111 0011
再保留符号位取反得到对应原码1000 1100:真值 -12
<<:左移
:将一个运算符对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)
左移1位后相当于a = a * 2;
int a = 11;// 11 简化补码:00001011System.out.println( a<<2);// 44
11 补码:0000 1011
a<<2结果:先右边补2位0:0000 1011 00,计算机位数不变左边溢出2位丢弃得到 0010 1100
最终补码:0001 0100:对应原码0010 1100真值:44
>> 右移(符号位填充)
:将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃
需要注意的是 >>带符号位填充,正补0 负补1
// 原值正数 左边补0int a = 11;// 11 简化补码:00001011System.out.println( a>>2);// 2
11 补码:0000 1011
a>>2结果:先左边补2位0:00 0000 1011,计算机位数不变右边丢弃2位得到 0000 0010对应值:2// 原值负数 左边补1int a = -11;// -11 补码:11111111 11111111 11111111 11110101System.out.println( a>>2);// -3
-11 补码:11111111 11111111 11111111 11110101
a>>2结果:先左边补2位1:11 11111111 11111111 11111111 11110101,
计算机位数不变右边丢弃2位得到11111111 11111111 11111111 1111 1101
首位为1代表负,先尾减1得到反码11111111 11111111 11111111 1111 1100
再保留符号位取反得对应简化原码1000 0011:真值 -3
>>>:无符号右移
:将一个数的各二进制位全部右移若干位,左补0 右边丢弃
区别于>>运算符,>>>:无符号右移 (不分正负)
// 原值正数int a = 11;// 11 补码:00001011System.out.println( a>>>2);// 2
11 补码:0000 1011
a>>>2结果:左补2位0:00 0000 1011,计算机位数不变右边丢弃2位得到 0000 0010对应值:2// 原值负数int a = -11;// -11 补码:11111111 11111111 11111111 11110101System.out.println( a>>>2);// -3
-11 补码:11111111 11111111 11111111 11110101
a>>>2结果:先左边补2位1:00 11111111 11111111 11111111 11110101,
计算机位数不变右边丢弃2位 00111111 11111111 11111111 11111101
首位0说明正数原码一样计算得到真值:1073741821
逻辑运算符
操作布尔值,用于条件组合判断,返回的结果是布尔类型的值
上面讲了位运算符& 和 | 直接操作整数的补码的计算逻辑,同时& 和 | 也可以作为逻辑运算符,用于判断
&:作为位运算符,二进制位同为1结果为1否则为0,操作的整数类型以补码形式
|:作为位运算符,二进制位一个为1结果就为1,操作的整数类型以补码形式
如果作为逻辑运算符
&:非短路与
:两边都为true时,结果才为true,否则为false
|:非短路或
:两边有一个结果为ture返回结果为1,两边都是false才返回false
&&:短路逻辑与
:类似于逻辑与&,区别在于短路操作
,如果有两个操作数,且第一个操作数为false,则不会评估第二个操作数,因为结果已经确定为false
||:短路逻辑或
:类似于逻辑或|,区别也是在于短路操作
,如果有两个操作数,且第一个操作数为true,则不会评估第二个操作数,因为结果已经确定为true
@Testpublic void test(){System.out.println(left(false) & right(true));// 两边都执行,即使左边已经得到flase 非短路System.out.println(left(true) | right(false));// 两边都执行,即使左边已经得到true 非短路System.out.println(left(false) && right(true));// 只走左边的方法 因为结果确定flase 短路System.out.println(left(true) || right(true));//都只走左边,因结果已经确定true 短路的System.out.println(left(true) || right(false));}public boolean left(boolean arg){System.out.println("left method Run...");return arg;}public boolean right(boolean arg){System.out.println("right method Run...");return arg;}
逻辑非(!)
:对操作数取反,如果操作数为true,则结果为false;如果操作数为false,则结果为true。 |
System.out.println(!true);//false 这个就是个反骨仔 取反的
赋值运算符
为变量赋值,可结合算术或位运算。
运算符 | 描述 | 等价于 | 示例 |
---|---|---|---|
= | 直接赋值 | a = 5 | |
+= | 加 后赋值 | a = a + b | 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 | a &= b |
l= | 按位或 后赋值 | a = a l b | a l= b |
^= | 按位异或 后赋值 | a = a ^ b | a ^= b |
<<= | 左移 后赋值 | a = a << b | a <<= b |
>>= | 右移 后赋值 | a = a >> b | a >>= b |
>>>= | 无符号右移 后赋值 | a = a >>> b | a >>>= b |
注意:复合赋值运算符隐含强制类型转换。
int a = 5;
a += 3.5; // 等价于 a = (int)(a + 3.5); → a=8
三元运算符(条件运算符)
简化条件判断,格式:条件 ? 表达式1 : 表达式2
。
示例:
int score = 85;
String result = score >= 60 ? "及格" : "不及格"; // result="及格"
其他运算符
运算符 | 描述 | 示例 | 说明 |
---|---|---|---|
instanceof | 类型检查 | obj instanceof String | 判断 obj 对象是否为 String 类型或其子类 |
() | 强制类型转换或优先级 | (int)3.14 , (a + b)*c | --------- |
运算符优先级
从高到低排列,同一行优先级相同:
优先级 | 运算符 |
---|---|
最高 | () [] . new instanceof |
++ -- ~ ! (单目) | |
* / % | |
+ - | |
<< >> >>> | |
< > <= >= | |
== != | |
& | |
^ | |
l | |
&& | |
ll | |
?: (三元) | |
最低 | = += -= 等赋值运算符 |
示例:
int result = 5 + 3 * 2; // 先乘后加 → 11
boolean flag = 5 > 3 && 2 < 4 || true; // 等效于 (5>3 && 2<4) || true → true
常见问题与技巧
- 整数除法陷阱
double a = 5 / 2; // a=2.0(整数除法)double b = 5 / 2.0; // b=2.5
- 短路逻辑优化代码
// 避免NullPointerException 这个非常重要if (obj != null && obj.value > 0) { ... }
这个非常重要,如果想要判断对象的某个属性值,需要先进行对象obj判空,否则执行obj.value > 0时候,可能会因为obj.value为空直接空指针,obj.value为null 有两种可能,一是obj为null,②是obj.value为null
public class MathTest {int a;public void test(){MathTest mathTest = new MathTest();System.out.println(mathTest.a);// 0System.out.println(mathTest.a > 0);// flase}
}
这里我也没有给成员变量 a赋值,这是因为对象实例创建后,会进行其属性(成员变量)初始化,如果我们定义了值,如int a=5,会给变量a赋值5,如果只是定义了变量没有赋值,会给变量a赋默认值0 或 null
,上面比较的是整数,所以默认值0,就不用判断obj.value为null,只需要判断obj对象是否存在就行
public class MathTest {String c;;public void test(){MathTest mathTest = new MathTest();System.out.println(mathTest.c);// 打印 nullSystem.out.println(mathTest.c.equals("c"));//NullPointerException}
}
对于如String类型的,默认值就是Null了,这时候就需要进行完整的Obj.value判空了
,至于可以打印输出 null那一步没有报错,是因为println方法对null对象做了一些特殊的处理,println方法会调用String.valueOf()方法来判断传入的对象是否为空,并返回需要打印的字符串。如果传入的引用类型对象是null,那么返回字符串null;如果不是null,则调用对象的toString方法,并打印字符串
-
位运算高效操作
- 判断奇偶:
(num & 1) == 0
- 交换变量:
a ^= b; b ^= a; a ^= b;
- 判断奇偶:
-
避免浮点数相等比较
// 错误方式if (x == y) { ... }// 正确方式if (Math.abs(x - y) < 1e-6) { ... }
“==”对于基础数量类型是比较其值,浮点数相等比较不推荐使用,是因为浮点数的存储和计算特性可能导致两个数学上相等的浮点数在计算机中不相等,我们推进使用java给的方法取比较浮点数的值