Java运算符完全指南:从基础到实战技巧

164 阅读6分钟

Java运算符完全指南:从基础到实战技巧

Java作为一门面向对象的编程语言,提供了丰富多样的运算符来操作各种数据类型。运算符是构建程序逻辑的基础组件,深入理解每个运算符的特性对于编写高效、健壮的Java代码至关重要。本文将逐一详解Java中的所有运算符,包括它们的语法、功能和使用场景。

一、算术运算符精讲

1. 加法运算符 (+)

int sum = 10 + 5;  // 结果为15
double total = 12.5 + 3.2;  // 结果为15.7
String concat = "Hello" + " " + "World";  // 字符串连接,结果为"Hello World"

特性:

  • 对数值执行加法运算
  • 对字符串执行连接操作
  • 当操作数中有一个是字符串时,另一个操作数会被自动转换为字符串

2. 减法运算符 (-)

int difference = 20 - 8;  // 结果为12
double negative = -15.5;  // 一元负号,结果为-15.5

特性:

  • 执行减法运算
  • 也可用作一元运算符表示负值

3. 乘法运算符 (*)

int product = 6 * 7;  // 结果为42
double area = 5.5 * 3.2;  // 结果为17.6

注意:

  • 整数乘法可能溢出,需要特别注意大数相乘的情况

4. 除法运算符 (/)

int quotient = 15 / 4;  // 整数除法,结果为3
double precise = 15.0 / 4;  // 浮点除法,结果为3.75

关键点:

  • 整数除法会截断小数部分
  • 至少有一个操作数是浮点数时执行浮点除法
  • 除以零会抛出ArithmeticException(整数)或得到Infinity(浮点数)

5. 取模运算符 (%)

int remainder = 17 % 5;  // 结果为2
double mod = 15.7 % 4.2;  // 浮点取模,约为3.1

特殊用途:

  • 检查奇偶性:num % 2 == 0
  • 循环缓冲区索引计算
  • 范围限制:value % range

6. 自增/自减运算符 (++/--)

int count = 5;
int post = count++;  // post=5, count=6
int pre = ++count;   // pre=7, count=7

区别:

  • 前缀形式(++x):先增减后使用
  • 后缀形式(x++):先使用后增减
  • 在复杂表达式中使用可能导致混淆,建议单独使用

二、关系运算符详解

1. 等于运算符 (==)

int a = 10, b = 20;
boolean eq1 = (a == b);  // false
String s1 = "hello", s2 = "hello";
boolean eq2 = (s1 == s2);  // true(由于字符串常量池)

注意事项:

  • 对于对象比较的是引用而非内容
  • 基本类型比较值,引用类型比较内存地址
  • 字符串内容比较应使用equals()方法

2. 不等于运算符 (!=)

int x = 15, y = 20;
boolean neq = (x != y);  // true

3. 大于运算符 (>)

double d1 = 12.5, d2 = 8.3;
boolean gt = (d1 > d2);  // true

4. 小于运算符 (<)

float f1 = 7.2f, f2 = 9.8f;
boolean lt = (f1 < f2);  // true

5. 大于等于运算符 (>=)

int score = 85;
boolean pass = (score >= 60);  // true

6. 小于等于运算符 (<=)

int age = 25;
boolean discount = (age <= 12 || age >= 65);  // 儿童或老人折扣

三、逻辑运算符深度解析

1. 逻辑与 (&&)

boolean b1 = true, b2 = false;
boolean and = b1 && b2;  // false

短路特性:

if (obj != null && obj.isValid()) {
    // 如果obj为null,不会调用isValid(),避免NullPointerException
}

2. 逻辑或 (||)

boolean b3 = true, b4 = false;
boolean or = b3 || b4;  // true

应用场景:

if (input.isEmpty() || !isValid(input)) {
    // 处理无效输入
}

3. 逻辑非 (!)

boolean flag = true;
boolean neg = !flag;  // false

使用技巧:

if (!file.exists()) {
    // 文件不存在的处理逻辑
}

4. 非短路逻辑运算符 (&和|)

int val = 0;
if (false & (++val > 0)) {}  // val变为1,右侧仍会计算
if (true | (++val > 0)) {}   // val变为2,右侧仍会计算

与短路版本的区别:

  • 总是计算两侧表达式
  • 也可用于位运算

四、位运算符全面剖析

1. 按位与 (&)

int bits1 = 0b1100;  // 12
int bits2 = 0b1010;  // 10
int result = bits1 & bits2;  // 0b1000 (8)

应用:

  • 掩码操作
  • 检查特定位是否设置

2. 按位或 (|)

int resOr = bits1 | bits2;  // 0b1110 (14)

用途:

  • 设置特定位
  • 组合标志位

3. 按位异或 (^)

int resXor = bits1 ^ bits2;  // 0b0110 (6)

特性:

  • 相同为0,不同为1
  • 可用于简单加密/解密
  • 交换两个变量的值:a ^= b; b ^= a; a ^= b;

4. 按位取反 (~)

int inverted = ~bits1;  // 0b...11110011 (-13)

注意:

  • 所有位取反,包括符号位
  • 结果是原值的"二的补码"负数减一

5. 左移 (<<)

int shifted = 0b0001 << 2;  // 0b0100 (4)

特点:

  • 相当于乘以2^n
  • 低位补0
  • 可能改变符号位

6. 右移 (>>)

int neg = -8;  // 0b111...1000
int sr = neg >> 1;  // 0b111...1100 (-4) 符号位扩展

说明:

  • 算术右移,保留符号位
  • 相当于除以2^n并向下取整

7. 无符号右移 (>>>)

int usr = neg >>> 1;  // 高位补0,结果变为很大的正数

区别:

  • 逻辑右移,高位总是补0
  • 对负数操作会得到非直观结果

五、赋值运算符详解

1. 简单赋值 (=)

int value = 42;
String message = "Hello";
Object obj = new Object();

2. 复合赋值运算符

int num = 10;
num += 5;   // num = 15
num -= 3;   // num = 12
num *= 2;   // num = 24
num /= 4;   // num = 6
num %= 5;   // num = 1
num <<= 2;  // num = 4
num >>= 1;  // num = 2
num &= 3;   // num = 2
num |= 5;   // num = 7
num ^= 4;   // num = 3

特点:

  • 更简洁的语法
  • 自动类型转换
  • 左侧操作数只计算一次,可能更高效

六、条件运算符 (? :)

int max = (a > b) ? a : b;
String status = (score >= 60) ? "及格" : "不及格";

最佳实践:

  • 适合简单的二选一情况
  • 复杂逻辑建议使用if-else
  • 避免嵌套使用,降低可读性

七、instanceof运算符

Object obj = "字符串";
if (obj instanceof String) {
    String s = (String) obj;
    System.out.println(s.length());
}

用途:

  • 类型检查
  • 避免ClassCastException
  • 在继承层次结构中判断具体类型

运算符优先级总结

优先级运算符结合性
1() [] .从左到右
2! ~ ++ -- +(一元) -(一元) (强制类型转换)从右到左
3* / %从左到右
4+ -从左到右
5<< >> >>>从左到右
6< <= > >= instanceof从左到右
7== !=从左到右
8&从左到右
9从左到右
10从左到右
11&&从左到右
12从左到右
13?:从右到左
14= += -= *= /= %= &= ^== <<= >>= >>>=从右到左

实战技巧与常见陷阱

  1. 整数溢出问题
int big = Integer.MAX_VALUE;
big += 1;  // 溢出为Integer.MIN_VALUE
  1. 浮点数比较
// 错误方式
if (f1 == f2) {...}

// 正确方式
if (Math.abs(f1 - f2) < 1e-10) {...}
  1. 字符串比较误区
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2);  // false
System.out.println(s1.equals(s2));  // true
  1. 位运算优化
// 判断奇偶
boolean isEven = (num & 1) == 0;

// 交换变量
a ^= b;
b ^= a;
a ^= b;
  1. 运算符优先级混淆
int result = 5 + 3 * 2;  // 11不是16
boolean flag = true || false && false;  // true(&&优先级高于||)

总结

Java运算符系统提供了强大而灵活的操作能力,从基本的算术运算到复杂的位操作,每种运算符都有其特定的用途和行为特点。掌握这些运算符的细节和微妙之处,能够帮助开发者:

  1. 编写更高效、更简洁的代码
  2. 避免常见的编程错误和陷阱
  3. 实现复杂的算法和数据处理逻辑
  4. 更好地理解和调试现有代码

记住,当运算符的使用可能引起混淆时,使用括号明确运算顺序总是明智的选择。同时,对于复杂的表达式,考虑将其分解为多个步骤或添加注释,以提高代码的可读性和可维护性。

通过本指南的系统学习,相信你已经对Java运算符有了全面而深入的理解。在实际编程中不断练习和应用这些知识,你的Java编程技能必将达到新的高度