一、算术运算符
2.1 基本四则运算符:+、-、*、/、%
这五个均为二元运算符,使用时必须具备左右两个操作数,分别对应加、减、乘、除、取模(求余数)运算。
代码示例:
java
public static void main(String[] args) {
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);
}
上述内容过于简单,不在过多赘述。
规则:
1、两个int类型做除法,结果仍然是int类型,会向下取整,直接舍弃小数部分。
**2、**做除法 / 和取模 % 运算时,右操作数不能为 0,否则程序运行时会抛出 ArithmeticException(算术异常),直接终止运行。
**3、取模运算的扩展:%**不仅支持整型取模,也可以对double等浮点类型取模,但浮点取模没有实际业务意义,实际开发几乎只对整型使用取模。
**4、**运算时的类型自动提升:当两个操作数类型不一致时,小范围类型会自动提升为大范围类型,再参与运算,最终结果为大范围类型。
2.2 增量运算符:+=、-=、*=、/=、%=
代码示例:
java
int a = 1;
a += 2; // 完全等价于:a = a + 2; 先相加,再将结果赋值给a
System.out.println(a); // 输出:3
a -= 1; // 等价于:a = a - 1;
System.out.println(a); // 输出:2
a *= 3; // 等价于:a = a * 3;
System.out.println(a); // 输出:6
a /= 3; // 等价于:a = a / 3;
System.out.println(a); // 输出:2
a %= 3; // 等价于:a = a % 3;(原文注释误写为%2,以此处为准)
System.out.println(a); // 输出:2
核心特性:内置强制类型转换
复合赋值运算符会自动对运算结果做强制类型转换,无需手动强转即可编译通过,这是它和普通算术赋值的核心区别。
java
double a = 10.4;
int b = 10;
b += a;
// 编译通过,等价于 b = (int)(b + a);
// 复合赋值会自动将右侧的double运算结果强转为int,再赋值给b
b = b + a;
// 编译报错:b+a运算后结果为double类型,大范围类型不能直接赋值给小范围的int
2.3 自增 / 自减运算符:++、--
++的作用是给变量的值加 1,--的作用是给变量的值减 1。二者属于单目运算符,只能操作变量,不能操作常量(常量的值不允许被修改)。
根据运算符与变量的位置,分为前置 和后置两种写法,差异仅在混合运算场景下体现。
一句话------与C语言完全相同。
二、关系运算符
共 6 个关系运算符:
相等判断:==(等于)、!=(不等于)
大小判断:<(小于)、>(大于)、<=(小于等于)、>=(大于等于)
规则:
**1、**禁止连写:Java 不支持数学中的连续比较写法,例如3 < a < 5是语法错误。
错误原因:3 < a的结果是 boolean 类型,无法再和整数 5 做大小比较。
正确写法:需要用逻辑运算符连接,写成 a > 3 && a < 5
**2、**适用范围:关系运算符可用于所有数值类型(byte、short、int、long、float、double、char)的比较;== 和 != 还可用于引用类型比较,但默认比较的是内存地址而非内容。
内容与C语言基本一致,不过多赘述。
三、逻辑运算符
逻辑运算符用于连接多个布尔表达式,组合成更复杂的判断条件,运算结果也为 boolean 类型。
核心有三个:&&(逻辑与)、||(逻辑或)、!(逻辑非)。
3.1 逻辑与 &&
1、语法规则: 表达式1 && 表达式2,左右两边的表达式都必须是布尔类型的结果。
2、语义:对应现实中的 "并且",两个条件同时满足,整体才成立。
3、运算规则 :全真才真,一假则假。只有两边都为 true,结果才是 true;只要有一个为 false,结果就是 false。
代码示例:
java
int a = 1;
int b = 2;
// 左边a==1为真,右边b==2为真,全真则真,结果:true
System.out.println(a == 1 && b == 2);
// 左边为真,右边b>100为假,一假则假,结果:false
System.out.println(a == 1 && b > 100);
// 左边a>100为假,右边为真,一假则假,结果:false
System.out.println(a > 100 && b == 2);
// 左右两边都为假,全假则假,结果:false
System.out.println(a > 100 && b > 100);
3.2 逻辑或 ||
1、语法规则: 表达式1 || 表达式2,左右两边的表达式都必须是布尔类型的结果。
2、语义:对应现实中的 "或者",两个条件只要满足一个,整体就成立。
3、运算规则 :一真则真,全假才假。只要有一边为 true,结果就是 true;两边都为 false,结果才是 false。
代码示例:
java
int a = 1;
int b = 2;
// 左右都为真,一真则真,结果:true
System.out.println(a == 1 || b == 2);
// 左边为真,右边为假,一真则真,结果:true
System.out.println(a == 1 || b > 100);
// 左边为假,右边为真,一真则真,结果:true
System.out.println(a > 100 || b == 2);
// 左右都为假,全假才假,结果:false
System.out.println(a > 100 || b > 100);
3.3 逻辑非 !
1、语法规则 :!表达式 ,属于单目运算符,只需要一个布尔类型的操作数。
2、语义:对布尔结果取反。
3、运算规则 :真变假,假变真。
3.4 短路
简单概括为4点:
1、短路规则:&&(短路与)只要左边结果为假,右边的代码就直接跳过不执行;||(短路或)只要左边结果为真,右边的代码就直接跳过不执行。这个特性能避开除零报错这类异常。
2、&、| 和 &&、|| 的区别:&和 | 也能做逻辑判断,但没有短路效果,不管左边结果如何,右边的代码一定会完整执行,所以可能触发程序异常。
3、实用要点 :逻辑运算符优先级从高到低是 ! > && > || ;实际开发统一用**&&** 和 ||,几乎不用&、| 做逻辑判断;常利用短路特性先判断变量非空,再调用方法,避免空指针报错。
四、位运算符
位运算是直接操作整数二进制比特位的运算,运算效率远高于普通算术运算,常用于底层开发、性能优化、标志位处理等场景。
Java 核心位运算符共 4 个:&(按位与)、|(按位或)、~(按位取反)、^(按位异或);其中~是单目运算符(仅操作一个数),其余均为二元运算符。 计算机中所有数据底层都以二进制(0 和 1 的序列)存储,位运算就是对二进制的每一位逐一进行逻辑计算。
4.1 按位与 &
运算规则: 两个二进制对应位都为 1 时,结果位才是 1;只要有一个是 0,结果位就是 0。

java
int a = 10; // 定义int变量a,十进制值为10
int b = 20; // 定义int变量b,十进制值为20
System.out.println(a & b); // 对a和b的二进制位逐位执行按位与运算,输出最终结果
最终结果对应十进制的 0
4.2 按位或 |
运算规则: 两个二进制对应位都为 0 时,结果位才是 0;只要有一个是 1,结果位就是 1。

java
int a = 10; // 定义int变量a,十进制值为10
int b = 20; // 定义int变量b,十进制值为20
System.out.println(a | b); // 对a和b的二进制位逐位执行按位或运算,输出最终结果
最终结果对应十进制的 30
重要补充:& 和 | 的双重身份
1、操作数是整数类型 (byte、short、int、long)时,执行位运算;
2、当操作数是boolean 类型 时,执行逻辑运算(不支持短路,左右两边表达式一定会全部执行)。
4.3 按位取反~
运算规则: 目运算符,对一个数的所有二进制位整体翻转:0 变成 1,1 变成 0,符号位也会一同翻转。
java
// 0x 是十六进制数字的固定前缀
// 0xf 表示十六进制的f,对应十进制15,二进制为 1111
int a = 0xf;
// printf 用于格式化输出
// %x 表示以十六进制格式输出结果,\n 是换行符
System.out.printf("%x\n", ~a);
按位取反会翻转符号位:正数取反后变为负数,负数取反后变为正数。
4.4 按位异或 ^
运算规则: 两个二进制对应位数值相同则结果为 0,数值不同则结果为 1。
java
int a = 0x1; // 十六进制1,对应十进制1,二进制为 0001
int b = 0x2; // 十六进制2,对应十进制2,二进制为 0010
// 对a和b执行按位异或运算,最终以十六进制格式输出
System.out.printf("%x\n", a ^ b);
五、移位运算符
移位运算符是对整数的二进制位进行整体平移的运算,共 3 种:<<(左移)、>>(带符号右移)、>>>(无符号右移),均为二元运算符,运算效率高于普通算术乘除,常用于底层性能优化场景。Java 中所有整数都以补码形式存储,移位操作均基于补码二进制执行。
5.1 左移 <<
运算规则: 将整数的二进制位整体向左移动指定位数:最左侧溢出的高位直接丢弃,最右侧空出的低位统一补 0。
java
// 0x10 是十六进制数,对应十进制16,二进制为 0001 0000
int a = 0x10;
// 将a的二进制位左移1位,最终结果以十六进制格式打印输出
System.out.printf("%x\n", a << 1);
// 运行结果(十六进制):20,对应十进制32,等价于 16 * 2^1 = 32
数学等价
对于正数且不溢出的场景,左移 N 位等价于原数乘以 2 的 N 次方,硬件执行效率远高于乘法运算。
符号位风险
左移时原符号位会随移位被溢出丢弃;如果左移位数足够多,最高位变为 1,正数会直接变成负数,发生数值溢出。
5.2 带符号右移 >>
也叫算术右移,核心特点是保留原数的正负符号。
运算规则: 将二进制位整体向右移动指定位数:最右侧低位直接丢弃,最左侧空出的高位补充符号位------ 正数补 0,负数补 1。
java
// 示例1:正数右移
int a = 0x10; // 十六进制10,对应十进制16,二进制高位全为0
System.out.printf("%x\n", a >> 1);
// 运行结果(十六进制):8,对应十进制8,等价于 16 / 2^1 = 8
// 示例2:负数右移
// 0xffff0000 是int类型的负数(最高位为1),对应十进制-65536
int b = 0xffff0000;
System.out.printf("%x\n", b >> 1);
// 运行结果(十六进制):ffff8000
// 原因:负数右移时,左侧补符号位1,因此结果依然是负数
数学等价
对于正数,右移 N 位等价于原数除以 2 的 N 次方(向下取整);负数右移后仍保持负数,数值向 0 的方向靠拢。
5.3 无符号右移 >>>
也叫逻辑右移,不区分正负,高位统一补 0。
运算规则: 将二进制位整体向右移动指定位数:最右侧低位直接丢弃,最左侧空出的高位统一补 0,无论原数是正数还是负数。
java
// 0xffffffff 是int类型的 -1,二进制所有位全部为1
int a = 0xffffffff;
// 无符号右移1位,左侧补0,结果以十六进制格式打印
System.out.printf("%x\n", a >>> 1);
// 运行结果(十六进制):7fffffff
// 原因:最高位补0后,原负数会直接变成一个很大的正整数
核心区别总结
>>(带符号右移):保留符号,正数补 0、负数补 1,适合有符号数的除法等价运算。
>>>(无符号右移):不保留符号,统一补 0,负数会变为正数,仅用于无符号数值处理场景。

六、条件运算符
语法格式:
java
表达式1 ? 表达式2 : 表达式3
执行逻辑
1、表达式 1 必须是boolean类型的结果(条件判断)。
2、当表达式 1 的值为true时,整个三目表达式的最终结果为表达式 2的值。
3、当表达式 1 的值为false时,整个三目表达式的最终结果为表达式 3的值。
java
// 需求:求两个整数a和b中的较大值
int a = 10; // 定义整型变量a,初始值10
int b = 20; // 定义整型变量b,初始值20
// 三目运算:判断a > b是否成立
// 成立则取a的值,不成立则取b的值,最终将结果赋值给max
int max = a > b ? a : b;
// 本例中a>b为false,因此max被赋值为b的值20
与C语言基本一致,不过多赘述。
七、运算符的优先级
在复合表达式中,运算按运算符优先级从高到低执行,而非严格从左到右。
易错示例:移位运算符的优先级陷阱
代码示例(错误写法,结果不符合预期)
java
// 需求:计算a和b的平均值,预期逻辑为 a + (b - a) / 2
int a = 10; // 定义整型变量a,初始值为10
int b = 20; // 定义整型变量b,初始值为20
int c = a + (b - a) >> 1;
/*
* 预期执行顺序(开发者的主观想法):
* 1. 先算括号内:b - a = 10
* 2. 再右移1位(等价于整数除以2):10 >> 1 = 5
* 3. 最后相加:a + 5 = 15
*
* 实际执行顺序(Java优先级规则):
* 算术运算符 + 的优先级 高于 移位运算符 >>
* 1. 先算括号内:b - a = 10
* 2. 再执行加法:a + 10 = 20
* 3. 最后执行右移:20 >> 1 = 10
* 最终结果为10,和预期的15完全不符
*/
System.out.println(c); // 运行输出:10
最佳实践与正确写法
运算符优先级无需死记硬背,遇到含多种运算符、易产生歧义的代码,主动加括号明确运算顺序是最稳妥的写法;括号优先级最高,可强制控制运算顺序,彻底规避优先级带来的逻辑错误。
java
// 需求:计算a和b的平均值
int a = 10; // 定义整型变量a,初始值为10
int b = 20; // 定义整型变量b,初始值为20
int c = a + ((b - a) >> 1);
/*
* 通过括号明确指定执行顺序,完全规避优先级问题:
* 1. 最内层括号:b - a = 10
* 2. 第二层括号:10 >> 1 = 5(正整数右移1位,等价于整数除法除以2)
* 3. 最后执行加法:10 + 5 = 15
* 结果完全符合平均值的预期逻辑
*/
System.out.println(c); // 运行输出:15
移位运算符补充说明
对于正整数,>> 1 的效果和整数除法 /2 完全一致,是底层优化的常见写法;但正是因为其优先级低于加减,混合运算时必须搭配括号使用。
工程编码规范
实际开发中永远不要依赖运算符优先级书写复杂表达式。哪怕优先级顺序是确定的,添加括号也能大幅提升代码可读性,降低后续维护的理解成本和出错概率。
学无止境,代码不息。今天的分享就到这儿,有错误或者更好的思路,欢迎大佬们指正交流 🤝📚