文章目录
-
- 一、运算符分类总览
- 二、单类运算符深度解析(含示例与原理)
-
- (一)算术运算符:数值计算的核心工具
-
- [1. 基本算术运算符(+、-、\*、/、%)](#1. 基本算术运算符(+、-、*、/、%))
- [2. 自增 / 自减运算符(++、--)](#2. 自增 / 自减运算符(++、--))
- (二)赋值运算符:变量赋值与简化运算
-
- [1. 基本赋值运算符(=)](#1. 基本赋值运算符(=))
- [2. 复合赋值运算符(+=、-=、\*=、/=、%= 等)](#2. 复合赋值运算符(+=、-=、*=、/=、%= 等))
- (三)比较运算符:判断关系的逻辑基础
-
- [1. 所有比较运算符详解](#1. 所有比较运算符详解)
- (四)逻辑运算符:布尔值的组合判断
-
- [1. 逻辑运算符分类与示例](#1. 逻辑运算符分类与示例)
- (五)位运算符:二进制位的高效操作
-
- [1. 位运算符分类与原理](#1. 位运算符分类与原理)
- [2. 典型应用场景:状态标记](#2. 典型应用场景:状态标记)
- [(六)条件运算符(?:):简化 if-else 的三目工具](#(六)条件运算符(?:):简化 if-else 的三目工具)
-
- [1. 语法与功能](#1. 语法与功能)
- [(七)instanceof 运算符:对象类型的判断工具](#(七)instanceof 运算符:对象类型的判断工具)
-
- [1. 语法与功能](#1. 语法与功能)
- 三、运算优先级与结合性:解决表达式运算顺序问题
-
- [1. 运算符优先级排序(从高到低,关键类别)](#1. 运算符优先级排序(从高到低,关键类别))
- [2. 优先级与结合性示例解析](#2. 优先级与结合性示例解析)
- 四、实践避坑指南(开发中高频错误)
- 五、总结:运算符的选择与使用原则
运算符是 Java 中实现数据计算、逻辑判断、赋值操作的核心语法元素,它基于基本数据类型(如 int、double、char 等)实现运算,按功能可分为 7 大类。掌握运算符的用法与特性,是编写正确、高效代码的基础,尤其需注意不同类型运算的转换规则与特殊场景(如溢出、短路逻辑)。
一、运算符分类总览
Java SE 的运算符按功能可划分为 7 大类,每类对应特定业务场景(如算术计算、条件判断),具体分类如下:
运算符类别 | 包含运算符 | 核心作用 | 操作数数量 |
---|---|---|---|
算术运算符 | +(加)、-(减)、*(乘)、/(除)、%(模)、++(自增)、--(自减) | 数值计算 | 双目(++/-- 为单目) |
赋值运算符 | =(基本赋值)、+=(加后赋值)、-=(减后赋值)、*=(乘后赋值)等 | 变量赋值与简化运算 | 双目 |
比较运算符 | ==(等于)、!=(不等于)、>(大于)、<(小于)、>=(大于等于)、<=(小于等于) | 判断两个值的关系 | 双目 |
逻辑运算符 | &&(短路与)、 | (短路或)、!(非)、&(逻辑与)、 | |
位运算符 | &(按位与)、 | (按位或)、^(按位异或)、~(按位取反)、<<(左移)、>>(右移)、>>>(无符号右移) | 二进制位级操作 |
条件运算符 | ?:(三目运算符) | 简化 if-else 判断的二选一赋值 | 三目 |
instanceof 运算符 | instanceof | 判断对象是否为指定类 / 接口实例 | 双目 |
二、单类运算符深度解析(含示例与原理)
(一)算术运算符:数值计算的核心工具
算术运算符用于整数、浮点数的计算,需注意整数除法截断 、模运算正负号 、自增 / 自减的前置与后置差异三大关键点。
1. 基本算术运算符(+、-、*、/、%)
-
语法 :
操作数1 运算符 操作数2
(双目运算符,需两个操作数) -
功能与示例:
运算符 | 功能 | 代码示例 | 结果 | 注意事项 |
---|---|---|---|---|
+ | 加法(含正号) | int a = 5 + 3; double b = 2.5 + 1.5; |
a=8 b=4.0 | 若操作数含 char,会自动转 Unicode 值计算(如'A' + 1 = 66 ) |
- | 减法(含负号) | int c = 10 - 4; double d = 5.0 - 2.3; |
c=6 d=2.7 | 负号可作单目运算符(如int e = -3; ,表示负数) |
* | 乘法 | int f = 3 * 4; double g = 2.0 * 3.5; |
f=12 g=7.0 | 整数相乘可能溢出(如int h = 2147483647 * 2; ,结果为负) |
/ | 除法 | int i = 10 / 3; double j = 10.0 / 3; |
i=3 j≈3.333 | 整数除法仅保留整数部分(截断,非四舍五入);除数不能为 0 |
% | 模运算(取余数) | int k = 10 % 3; int l = -10 % 3; |
k=1 l=-1 | 结果符号与被除数 一致;浮点数也支持模运算(如5.5 % 2.0 = 1.5 ) |
-
关键避坑点:
-
整数除法截断:
7 / 2 = 3
(非 3.5),若需小数结果,需将任一操作数转为浮点数(如7.0 / 2 = 3.5
); -
除数不能为 0:整数除法除数为 0 会抛
ArithmeticException
(如5 / 0
),浮点数除法除数为 0 会得到Infinity
(如5.0 / 0 = Infinity
)。
-
2. 自增 / 自减运算符(++、--)
-
语法 :
++变量
(前置自增)、变量++
(后置自增);--变量
(前置自减)、变量--
(后置自减)(单目运算符,仅需一个操作数) -
核心差异:前置先运算再赋值,后置先赋值再运算;
-
代码示例与解析:
// 自增示例
int x = 5;
int y = ++x; // 前置自增:x先+1(x=6),再赋值给y → y=6
int z = x++; // 后置自增:先将x=6赋值给z(z=6),再x+1(x=7)
System.out.println(x); // 7
System.out.println(y); // 6
System.out.println(z); // 6
// 自减示例
int m = 3;
int n = --m; // 前置自减:m先-1(m=2),再赋值给n → n=2
int p = m--; // 后置自减:先将m=2赋值给p(p=2),再m-1(m=1)
System.out.println(m); // 1
System.out.println(n); // 2
System.out.println(p); // 2
-
注意事项:
-
自增 / 自减仅适用于变量(如
++5
报错,不能操作常量); -
避免在复杂表达式中使用(如
int q = x++ + ++x
,结果依赖编译器,可读性差)。
-
(二)赋值运算符:变量赋值与简化运算
赋值运算符的核心是=
,其他均为 "运算 + 赋值" 的复合简化形式,可自动处理类型转换(如byte += int
无需强制转换)。
1. 基本赋值运算符(=)
-
语法 :
变量 = 表达式
-
功能:将右侧表达式结果赋值给左侧变量(左侧必须是可修改的变量,不能是常量或表达式);
-
代码示例:
int a = 10; // 直接赋值常量
double b = 3.14; // 赋值浮点数
int c = a + 5; // 赋值表达式结果(a+5=15 → c=15)
// 错误示例:左侧不能是常量或表达式
// 10 = a; // 报错:左侧必须是变量
// a + b = 20; // 报错:左侧必须是变量
2. 复合赋值运算符(+=、-=、*=、/=、%= 等)
-
语法 :
变量 复合运算符 表达式
→ 等价于变量 = (变量类型) (变量 运算符 表达式)
(自动隐含强制类型转换); -
功能与示例:
运算符 | 等价写法 | 代码示例 | 结果 | 隐含转换说明 |
---|---|---|---|---|
+= | 变量 = 变量 + 表达式 | byte x = 5; x += 3; (等价 x=(byte)(x+3)) |
x=8 | 若表达式是 int(如 3),自动转 byte(避免x = x + 3 的编译错误) |
-= | 变量 = 变量 - 表达式 | int y = 10; y -= 4; |
y=6 | 无类型转换问题(同类型运算) |
*= | 变量 = 变量 * 表达式 | double z = 2.5; z *= 2; |
z=5.0 | 浮点数运算保留小数 |
/= | 变量 = 变量 / 表达式 | int m = 10; m /= 3; |
m=3 | 整数除法截断 |
%= | 变量 = 变量 % 表达式 | int n = 10; n %= 3; |
n=1 | 结果符号与被除数一致 |
- 关键优势 :复合赋值运算符可避免 "类型不匹配" 的编译错误(如
byte
与int
运算),无需手动强制转换。
(三)比较运算符:判断关系的逻辑基础
比较运算符用于判断两个值的大小或相等关系,结果仅为 boolean 类型(true/false),常用于 if 条件、while 循环的判断条件。
1. 所有比较运算符详解
-
语法 :
操作数1 运算符 操作数2
(双目运算符) -
功能与示例(基于 int、double、String 的比较):
// 1. 数值比较(int/double)
int a = 5, b = 3;
double c = 2.5, d = 2.5;
System.out.println(a > b); // true(5>3)
System.out.println(a < b); // false(5<3)
System.out.println(a >= 5); // true(5>=5)
System.out.println(b <= 2); // false(3<=2)
System.out.println(c == d); // true(2.5==2.5)
System.out.println(c != d); // false(2.5!=2.5)
// 2. 字符串比较(注意:String是引用类型,==比较地址,equals()比较内容)
String s1 = "abc";
String s2 = new String("abc");
System.out.println(s1 == s2); // false(s1和s2地址不同)
System.out.println(s1.equals(s2)); // true(s1和s2内容相同)
-
关键避坑点:
-
引用类型(如 String、自定义类)的
==
比较 "内存地址",而非内容;比较内容需用equals()
方法(如 String 的equals()
); -
浮点数比较避免直接用
==
:因精度问题(如0.1 + 0.2 = 0.30000000000000004
),需用 "差值绝对值小于极小值" 判断(如Math.abs(0.1+0.2 - 0.3) < 1e-9
)。
-
(四)逻辑运算符:布尔值的组合判断
逻辑运算符用于连接多个 boolean 表达式(或单个 boolean 值),核心分为短路逻辑(&&、||) 与非短路逻辑(&、|),差异在于 "是否提前终止运算"。
1. 逻辑运算符分类与示例
-
语法 :
布尔表达式1 逻辑运算符 布尔表达式2
(!
为!布尔表达式
) -
功能对比与代码示例:
运算符 | 类型 | 功能(布尔值 a、b) | 短路特性 | 代码示例(a=true, b=false) | 结果 |
---|---|---|---|---|---|
&& | 短路与 | a 且 b:均为 true 则 true,否则 false | 左假则右不执行 | (a == true) && (++b == true) |
true |
短路或 | a 或 b:任一为 true 则 true,否则 false | 左真则右不执行 | |||
& | 非短路与 | 同 &&,但无论左值如何,右值必执行 | 无 | (a == true) & (++b == true) |
true |
非短路或 | 同 | ,但无论左值如何,右值必执行 | |||
! | 非(取反) | 真变假,假变真 | - | !(a == true) |
false |
^ | 异或 | a 和 b 不同则 true,相同则 false | 无 | (a == true) ^ (b == true) |
true |
-
核心应用场景:
-
短路逻辑(&&、||):用于 "无需执行所有表达式" 的场景(如判断 "用户不为 null 且用户名正确":
user != null && user.getName().equals("admin")
,避免user为null时调用getName()抛空指针异常
); -
非短路逻辑(&、|):用于 "必须执行所有表达式" 的场景(如同时判断两个条件并记录日志,右表达式为日志打印代码)。
-
(五)位运算符:二进制位的高效操作
位运算符直接操作整数的二进制位(如 byte、short、int、long),运算效率极高,常用于状态标记 、数值压缩 、高性能计算场景(如网络协议、底层开发)。
1. 位运算符分类与原理
整数在内存中以 "补码" 形式存储,位运算直接操作补码的每一位(0 表示 false,1 表示 true),具体运算符如下:
运算符 | 类型 | 功能(二进制位 a、b) | 代码示例(int a=6→0110, b=3→0011) | 结果(二进制→十进制) |
---|---|---|---|---|
& | 按位与 | a&b:同 1 则 1,否则 0 | a & b |
0010 → 2 |
按位或 | a | b:同 0 则 0,否则 1 | ||
^ | 按位异或 | a^b:不同则 1,相同则 0 | a ^ b |
0101 → 5 |
~ | 按位取反 | ~a:0 变 1,1 变 0(含符号位) | ~a |
11111111111111111111111111111001 → -7 |
<< | 左移 | a<<n:a 的二进制左移 n 位,右补 0 | a << 2 |
011000 → 24 |
>> | 右移 | a>>n:a 的二进制右移 n 位,左补符号位 | a >> 2 |
0001 → 1 |
>>> | 无符号右移 | a>>>n:a 的二进制右移 n 位,左补 0 | a >>> 2 |
0001 → 1 |
-
关键解析:
-
按位取反(~):int 是 32 位,取反后符号位变 1(负数),结果为 "-(原数 + 1)"(如
~6 = -7
); -
左移(<<):等价于 "a × 2^n"(如
6<<2 = 6×4=24
),无符号扩展; -
右移(>>):正数左补 0,负数左补 1(如
-6>>2 = -2
);无符号右移(>>>):无论正负左补 0(如-6>>>2 = 1073741822
)。
-
2. 典型应用场景:状态标记
用一个 int 的不同二进制位表示多个状态(如 "用户权限":位 0 表示 "读",位 1 表示 "写",位 2 表示 "删"),通过位运算高效判断 / 修改状态:
// 定义状态位(每个状态占1位)
int READ = 1 << 0; // 0001(读权限)
int WRITE = 1 << 1; // 0010(写权限)
int DELETE = 1 << 2;// 0100(删权限)
// 给用户分配权限(按位或 |:添加权限)
int userPerm = READ | WRITE; // 0011(有读、写权限)
// 判断用户是否有某权限(按位与 &:结果非0则有)
boolean hasRead = (userPerm & READ) != 0; // true(有读权限)
boolean hasDelete = (userPerm & DELETE) != 0;// false(无删权限)
// 给用户添加删权限(按位或 |)
userPerm = userPerm | DELETE; // 0111(读、写、删权限)
// 给用户移除写权限(按位异或 ^:移除已有的位)
userPerm = userPerm ^ WRITE; // 0101(读、删权限)
(六)条件运算符(?:):简化 if-else 的三目工具
条件运算符是 Java 中唯一的三目运算符,用于 "根据条件二选一赋值",可简化简单的 if-else 逻辑,提高代码简洁性。
1. 语法与功能
-
语法 :
条件表达式 ? 表达式1 : 表达式2
-
逻辑 :若条件表达式为
true
,执行表达式 1 并返回结果;否则执行表达式 2 并返回结果; -
核心要求 :表达式 1 与表达式 2 的返回值类型必须兼容(可自动转换或相同类型);
-
代码示例:
// 场景1:判断两个数的最大值
int a = 5, b = 8;
int max = (a > b) ? a : b; // 条件为false,返回b → max=8
// 场景2:判断学生成绩是否及格
int score = 75;
String result = (score >= 60) ? "及格" : "不及格"; // 条件为true,返回"及格"
// 场景3:类型兼容(int自动转double)
double num = (a > b) ? 10 : 3.5; // 表达式1(10)转double → num=3.5
-
注意事项:
-
避免嵌套过深(如
a>b ? (a>c ? a:c) : (b>c ? b:c)
),可读性差,复杂逻辑建议用 if-else; -
表达式 1 与表达式 2 不能是 void 类型(必须有返回值,如
(a>b) ? System.out.println(a) : System.out.println(b)
报错)。
-
(七)instanceof 运算符:对象类型的判断工具
instanceof 用于判断 "对象是否为指定类的实例" 或 "对象是否实现指定接口",返回 boolean 类型,常用于多态场景中的类型判断(如向下转型前的安全检查)。
1. 语法与功能
-
语法 :
对象 instanceof 类/接口
-
核心规则:
-
若对象为
null
,结果恒为false
; -
若对象是指定类的实例(包括子类实例),或实现指定接口,结果为
true
;
-
-
代码示例:
// 定义父类、子类与接口
class Animal {}
class Dog extends Animal implements Runnable {}
interface Runnable {}
// 创建对象
Animal animal = new Dog();
Dog dog = new Dog();
Runnable runnable = new Dog();
// instanceof判断
System.out.println(animal instanceof Animal); // true(animal是Animal实例)
System.out.println(animal instanceof Dog); // true(animal是Dog实例,Dog是Animal子类)
System.out.println(animal instanceof Runnable); // true(animal是Runnable实现类实例)
System.out.println(dog instanceof Animal); // true(Dog是Animal子类)
System.out.println(runnable instanceof Dog); // true(runnable是Dog实例)
System.out.println(null instanceof Animal); // false(null无类型)
-
应用场景 :向下转型前的安全检查(避免
ClassCastException
):Animal a = new Dog();
// 安全转型:先判断是否为Dog实例
if (a instanceof Dog) {
Dog d = (Dog) a; // 向下转型,安全无异常
}
三、运算优先级与结合性:解决表达式运算顺序问题
当一个表达式包含多个运算符时,优先级高的运算符先执行 ;若优先级相同,按结合性 (从左到右或从右到左)执行。无需死记优先级,复杂表达式建议用括号 () 明确顺序(可读性更高)。
1. 运算符优先级排序(从高到低,关键类别)
优先级 | 运算符类别 | 具体运算符(示例) | 结合性 |
---|---|---|---|
1 | 括号 | () | 从左到右 |
2 | 单目运算符 | ++、--、!、~、+(正号)、-(负号) | 从右到左 |
3 | 算术运算符 | *、/、% | 从左到右 |
4 | 算术运算符 | +、- | 从左到右 |
5 | 位运算符 | <<、>>、>>> | 从左到右 |
6 | 比较运算符 | >、<、>=、<= | 从左到右 |
7 | 比较运算符 | ==、!= | 从左到右 |
8 | 位运算符 | & | 从左到右 |
9 | 位运算符 | ^ | 从左到右 |
10 | 位运算符 | ||
11 | 逻辑运算符 | && | 从左到右 |
12 | 逻辑运算符 | ||
13 | 条件运算符 | ?: | 从右到左 |
14 | 赋值运算符 | =、+=、-=、*= 等 | 从右到左 |
2. 优先级与结合性示例解析
// 示例1:算术运算符优先级(\*、/高于+、-)
int a = 3 + 4 \* 2; // 先算4\*2=8,再算3+8=11 → a=11
int b = (3 + 4) \* 2; // 括号优先级最高,先算3+4=7,再算7\*2=14 → b=14
// 示例2:赋值运算符结合性(从右到左)
int c = d = 5; // 先算d=5,再算c=d → c=5, d=5
// 示例3:单目运算符与算术运算符(单目高于算术)
int e = -3 + 5; // 先算-3(单目负号),再算-3+5=2 → e=2
// 示例4:逻辑运算符优先级(&&高于||)
boolean f = true || false && false; // 先算false&\&false=false,再算true||false=true → f=true
四、实践避坑指南(开发中高频错误)
-
整数溢出问题:
整数运算(如 int 的最大值 + 1)会溢出且无报错,需用
long
接收结果或手动判断(如if (a > Integer.MAX_VALUE - b) { 抛出溢出异常 }
); -
浮点数比较用 ==:
因精度问题(如
0.1+0.2≠0.3
),需用Math.abs(结果-预期值) < 1e-9
判断; -
String 用 == 比较内容:
String 是引用类型,
==
比较地址,比较内容必须用equals()
(空指针安全写法:"abc".equals(s)
,避免s.equals("abc")
); -
短路逻辑的空指针风险:
若左表达式为 false(&&)或 true(||),右表达式不执行,需确保左表达式能过滤无效场景(如
user != null && user.getName().equals("admin")
,避免 user 为 null 时调用 getName ()); -
自增 / 自减在复杂表达式中滥用:
如
int x = 5; int y = x++ + ++x;
(结果依赖编译器),建议拆分为多行代码(可读性更高,避免歧义); -
位运算用于浮点数:
位运算符仅支持整数类型(byte、short、int、long),浮点数需先转整数(如
(int)3.5 & 1
),否则编译报错。
五、总结:运算符的选择与使用原则
-
优先用短路逻辑(&&、||):减少无效运算,避免空指针异常(如判断对象非 null 后再调用方法);
-
复杂表达式用括号:无需依赖优先级,括号能明确运算顺序,提高代码可读性;
-
位运算用于高性能场景:如状态标记、数值压缩(比普通 if-else 效率更高);
-
条件运算符简化简单判断:仅用于 "二选一赋值" 场景,复杂逻辑用 if-else(避免嵌套);
-
类型转换需显式 :除复合赋值运算符的隐含转换外,不同类型运算需手动强制转换(如
int a = (int)3.5
),避免编译错误。
掌握 Java SE 运算符,需结合基本数据类型的特性(如 int 的范围、double 的精度),通过大量实践理解不同场景的正确用法,才能避免常见错误,编写高效、健壮的代码。