运算符是 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结果符号与被除数一致
  • 关键优势:复合赋值运算符可避免 “类型不匹配” 的编译错误(如byteint运算),无需手动强制转换。

(三)比较运算符:判断关系的逻辑基础

比较运算符用于判断两个值的大小或相等关系,结果仅为 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,否则 0a & b0010 → 2
按位或ab:同 0 则 0,否则 1
^按位异或a^b:不同则 1,相同则 0a ^ b0101 → 5
~按位取反~a:0 变 1,1 变 0(含符号位)~a11111111111111111111111111111001 → -7
<<左移a<<n:a 的二进制左移 n 位,右补 0a << 2011000 → 24
>>右移a>>n:a 的二进制右移 n 位,左补符号位a >> 20001 → 1
>>>无符号右移a>>>n:a 的二进制右移 n 位,左补 0a >>> 20001 → 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

四、实践避坑指南(开发中高频错误)

  1. 整数溢出问题

    整数运算(如 int 的最大值 + 1)会溢出且无报错,需用long接收结果或手动判断(如if (a > Integer.MAX_VALUE - b) { 抛出溢出异常 });

  2. 浮点数比较用 ==

    因精度问题(如0.1+0.2≠0.3),需用Math.abs(结果-预期值) < 1e-9判断;

  3. String 用 == 比较内容

    String 是引用类型,==比较地址,比较内容必须用equals()(空指针安全写法:"abc".equals(s),避免s.equals("abc"));

  4. 短路逻辑的空指针风险

    若左表达式为 false(&&)或 true(||),右表达式不执行,需确保左表达式能过滤无效场景(如user != null && user.getName().equals("admin"),避免 user 为 null 时调用 getName ());

  5. 自增 / 自减在复杂表达式中滥用

    int x = 5; int y = x++ + ++x;(结果依赖编译器),建议拆分为多行代码(可读性更高,避免歧义);

  6. 位运算用于浮点数

    位运算符仅支持整数类型(byte、short、int、long),浮点数需先转整数(如(int)3.5 & 1),否则编译报错。

五、总结:运算符的选择与使用原则

  1. 优先用短路逻辑(&&、||):减少无效运算,避免空指针异常(如判断对象非 null 后再调用方法);

  2. 复杂表达式用括号:无需依赖优先级,括号能明确运算顺序,提高代码可读性;

  3. 位运算用于高性能场景:如状态标记、数值压缩(比普通 if-else 效率更高);

  4. 条件运算符简化简单判断:仅用于 “二选一赋值” 场景,复杂逻辑用 if-else(避免嵌套);

  5. 类型转换需显式:除复合赋值运算符的隐含转换外,不同类型运算需手动强制转换(如int a = (int)3.5),避免编译错误。

掌握 Java SE 运算符,需结合基本数据类型的特性(如 int 的范围、double 的精度),通过大量实践理解不同场景的正确用法,才能避免常见错误,编写高效、健壮的代码。