一、算术运算符

1.1 基本运算符

运算符 名称 示例 说明
+ 加法 a + b 也可用于字符串拼接
- 减法 a - b
* 乘法 a * b
/ 除法 a / b 整数除法截断小数,非四舍五入
% 取余 a % b 返回除法余数

1.2 整数除法

整数除法直接丢弃小数部分,不进行四舍五入:

int a = 7 / 2;   // 结果:3
int b = 5 / 10;  // 结果:0

若需保留小数,至少一个操作数为浮点类型:

double c = 7.0 / 2;           // 3.5
double d = (double) 7 / 2;    // 3.5

常见错误:double result = 7 / 2; 结果为 3.0,因整数除法优先于隐式转换。

1.3 取余运算

int r1 = 10 % 3;   // 1
int r2 = 15 % 5;   // 0
int r3 = -7 % 3;   // -1(符号与被除数一致)

典型应用:判断奇偶 — num % 2 == 0

1.4 自增自减(++ / --)

形式 名称 行为
++a 前缀自增 先加 1,再使用新值
a++ 后缀自增 先使用原值,再加 1
--a 前缀自减 先减 1,再使用新值
a-- 后缀自减 先使用原值,再减 1
int a = 5;
int b = ++a;  // a = 6, b = 6

int c = 5;
int d = c++;  // d = 5, c = 6

表达式中的执行顺序:

int a = 1;
int b = a++ + ++a;
// a++:返回 1,a 变为 2
// ++a:a 变为 3,返回 3
// b = 1 + 3 = 4
// 最终:a = 3, b = 4

规范建议:同一表达式中不对同一变量多次使用自增/自减,建议拆分。


二、字符串拼接

2.1 拼接规则

+ 运算符的语义取决于操作数类型:当任一操作数为 String 时,执行字符串拼接;否则执行数值加法。

System.out.println(1 + 2 + "3");   // "33"  → (1+2)=3, 再拼接 "3"
System.out.println("1" + 2 + 3);   // "123" → 从左到右依次拼接

若非字符串操作数的计算需优先执行,使用括号:

System.out.println("和:" + (10 + 20));  // "和:30"

2.2 char 类型与拼接

char ch = 'A';                          // ASCII 65
System.out.println(ch + 1);             // 66(算术运算)
System.out.println("字母:" + ch + 1);   // "字母:A1"
System.out.println("字母:" + (ch + 1)); // "字母:66"
System.out.println("字母:" + (char)(ch + 1)); // "字母:B"

2.3 性能说明

循环中频繁使用 + 拼接会创建大量临时 String 对象,推荐使用 StringBuilder

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append(i);
}
String result = sb.toString();

三、赋值运算符

3.1 简单赋值与链式赋值

= 为右结合运算符,从右向左执行:

int a, b, c;
a = b = c = 10;
// 等价于 a = (b = (c = 10));
// 执行顺序:c=10 → b=10 → a=10

3.2 复合赋值

运算符 示例 等价形式
+= a += 3 a = a + 3
-= a -= 2 a = a - 2
*= a *= 4 a = a * 4
/= a /= 2 a = a / 2
%= a %= 3 a = a % 3
&= a &= b a = a & b
` =` `a
^= a ^= b a = a ^ b
<<= a <<= 2 a = a << 2
>>= a >>= 1 a = a >> 1
>>>= a >>>= 1 a = a >>> 1

重要特性 — 自动类型强转:

Java 语言规范规定:E1 op= E2 等价于 E1 = (T)((E1) op (E2)),其中 T 为 E1 的类型。复合赋值自动执行窄化转换:

short s = 10;
s = s + 5;   // 编译错误:s + 5 结果为 int
s += 5;      // 正确:等价于 s = (short)(s + 5)

byte b = 10;
b += 100;    // 正确:自动强转
b = b + 100; // 编译错误

3.3 常见问题

  • 浮点字面量默认为 doublefloat f = 3.14; 编译错误,正确写法 float f = 3.14f;
  • 不支持对常量/表达式赋值:5 = a; 和 (a + b) = 10; 均为非法

四、关系运算符

4.1 运算符列表

运算符 名称 示例 返回值
== 等于 a == b boolean
!= 不等于 a != b boolean
< 小于 a < b boolean
<= 小于等于 a <= b boolean
> 大于 a > b boolean
>= 大于等于 a >= b boolean

关系运算符适用于所有基本数值类型和引用类型。字符间也可比较(基于 Unicode 值)。

4.2 == 与 equals()

  • 基本类型:== 比较值
  • 引用类型:== 比较内存地址,equals() 比较内容(需类正确重写)
String s1 = "Hello";                  // 字符串常量池
String s2 = new String("Hello");      // 堆中新对象

System.out.println(s1 == s2);         // false(地址不同)
System.out.println(s1.equals(s2));    // true(内容相同)

字符串常量池特性:

String s3 = "abc";
String s4 = "abc";
System.out.println(s3 == s4);    // true(同一常量池对象)

规范建议:字符串内容比较统一使用 equals()

4.3 浮点数比较

二进制无法精确表示十进制小数 0.1、0.2、0.3(在二进制中均为无限循环小数),导致精度误差:

double a = 0.1 + 0.2;
System.out.println(a);           // 0.30000000000000004
System.out.println(a == 0.3);    // false

安全比较方案:

// 方案一:误差范围(适用一般计算)
public static boolean isEqual(double a, double b) {
    return Math.abs(a - b) < 1e-9;
}

// 方案二:BigDecimal(适用精确计算,如金融场景)
BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
BigDecimal sum = a.add(b);
System.out.println(sum.equals(new BigDecimal("0.3"))); // true

注意:BigDecimal 构造必须使用字符串参数,new BigDecimal(0.1) 已携带精度误差。

4.4 关系运算符限制

操作数组合 是否允许 说明
boolean 与 boolean 允许 仅 == 和 !=
boolean 与数值 不允许 编译错误
对象与对象 允许 仅 == 和 !=,比较引用地址

五、逻辑运算符

5.1 基本逻辑运算符

运算符 名称 真值表 短路
& 逻辑与 全 true 则 true
` ` 逻辑或 有 true 则 true
^ 逻辑异或 不同为 true,相同为 false
! 逻辑非 取反
&& 短路与 同 &
` ` 短路或

5.2 短路与非短路的区别

短路运算符在左侧结果可确定整体结果时,跳过右侧表达式的执行:

String str = null;
if (str != null && str.length() > 0) {   // 安全:str 为 null 时右侧不执行
    // ...
}
// if (str != null & str.length() > 0)   // 危险:右侧必执行,抛出 NullPointerException
int a = 1;
boolean r1 = (a > 2) && (a++ > 0);   // r1 = false, a = 1(短路,a++ 未执行)
boolean r2 = (a > 2) & (a++ > 0);    // r2 = false, a = 2(非短路,a++ 已执行)

5.3 异或应用

// 布尔值翻转
boolean flag = true;
flag = flag ^ true;  // false
flag = flag ^ true;  // true

// 整数交换(不推荐用于生产代码)
int a = 5, b = 10;
a = a ^ b;
b = a ^ b;
a = a ^ b;
// 结果:a = 10, b = 5

5.4 使用建议

  • 条件判断优先使用 && 和 ||(短路,更安全)
  • & 仅用于:需要两侧均执行(如右侧有副作用)或位运算场景
  • ^ 不可用于幂运算,Java 中幂运算使用 Math.pow()

六、三元运算符

6.1 语法

condition ? expr1 : expr2

条件为 true 返回 expr1,否则返回 expr2expr1 与 expr2 类型需兼容。

int max = a > b ? a : b;

6.2 优先级

三元运算符优先级仅高于赋值运算符,低于逻辑运算符:

int result = true || false ? 10 : 20;
// 等价于 (true || false) ? 10 : 20,结果为 10

6.3 使用原则

  • 适用于简单的二选一赋值
  • 避免嵌套,多层嵌套应改用 if-else
  • 建议用括号明确运算顺序

七、运算符优先级

7.1 优先级表(降序)

优先级 运算符类别 运算符 结合性
1 括号 ()
2 单目 ! - ++ --
3 算术 * / %
4 算术 + -
5 位移 << >> >>>
6 关系 < <= > >= instanceof
7 相等 == !=
8 位与 &
9 位异或 ^
10 位或 ` `
11 逻辑与 &&
12 逻辑或 `
13 三元 ?:
14 赋值 = += -= 等

7.2 关键规则

  1. 括号优先级最高,不确定时使用括号明确意图
  2. 大方向:算术 > 关系 > 逻辑 > 三元 > 赋值
  3. && 优先级高于 ||
// 示例
boolean r1 = 3 + 5 > 7 && 9 - 2 < 8;     // (8>7) && (7<8) → true
boolean r2 = true || false && true;       // true || (false && true) → true
int res = (1 + 2) * 3;                   // 9

八、类型转换

8.1 隐式转换(自动类型提升)

从小范围到大范围自动转换,遵循提升链:

byte → short → int → long → float → double

表达式中的类型提升:

byte a = 1, b = 2;
// byte sum = a + b;  // 编译错误:结果提升为 int
int sum = a + b;       // 正确

char 可参与整数提升:

char c = 'A';      // ASCII 65
int n = c;         // 65

8.2 强制转换(显式类型转换)

大范围到小范围使用 (目标类型) 语法,可能导致精度丢失或溢出:

double d = 123.89;
int i = (int) d;        // 123(截断,非四舍五入)

int x = 300;
byte b = (byte) x;      // 44(溢出:300 - 256 = 44)

8.3 转换限制

  • boolean 与任何数值类型之间不可互转
  • char 与 int/long 等整数类型可互转(char 为 16 位无符号整数)

8.4 编译期常量优化

byte b = 100;           // 正确:100 在 byte 范围内,编译期确定
int i = 100;
// byte b2 = i;         // 错误:i 为变量,编译器无法确定范围
byte b3 = (byte) i;     // 正确:显式强转

九、常见问题

Q1:short s = 1; s = s + 1; 与 s += 1; 的区别?

s = s + 1 编译错误,因 s + 1 结果为 int,不可直接赋值给 shorts += 1 正确,复合赋值自动执行 (short)(s + 1) 强转。

Q2:"abc" == "abc" 与 new String("abc") == "abc"

前者 true(同一常量池对象),后者 false(堆中新建对象)。字符串内容比较应统一使用 equals()

Q3:0.1 + 0.2 == 0.3 为何为 false

十进制小数 0.1、0.2、0.3 在二进制中为无限循环小数,double 只能存储近似值。0.1+0.2 的近似结果约等于 0.30000000000000004。

Q4:& 与 && 的核心区别?

& 两侧均执行(非短路),&& 左侧为 false 时跳过右侧(短路)。条件判断应使用 &&,位运算使用 &

Q5:int a = 5; int b = (a = 3) + 2; 的结果?

a = 3, b = 5。(a = 3) 先执行赋值并返回值 3,因此 b = 3 + 2 = 5。体现赋值运算符的返回值特性。


更多推荐