1. 运算符与表达式基础概念
在Java编程语言中,运算符和表达式是构建程序逻辑的基础砖块。就像建筑工人需要了解不同工具的使用方法一样,程序员必须熟练掌握各种运算符的特性和表达式的组合方式。
表达式可以简单理解为"能计算出值的代码片段",它由操作数和运算符组成。例如在 3 + 4 * 2 这个表达式中,数字是操作数,+ 和 * 是运算符。Java编译器会按照特定规则计算这个表达式,最终得到结果11(注意乘法优先级高于加法)。
新手常见误区:很多初学者会误认为表达式计算顺序总是从左到右,实际上Java有严格的运算符优先级规则,就像数学中的"先乘除后加减"一样。
2. Java运算符全面解析
2.1 算术运算符
算术运算符是我们最熟悉的类型,包含以下7种:
- 基本四则运算:
+(加)、-(减)、*(乘)、/(除) - 取模运算:
%(求余数) - 自增自减:
++、--
特别需要注意的是整数除法的特性:
java复制int a = 5 / 2; // 结果是2而不是2.5,因为两个整数相除结果还是整数
double b = 5 / 2.0; // 这样才会得到2.5
自增运算符有前置和后置的区别:
java复制int x = 5;
int y = x++; // y=5, x=6
int z = ++x; // z=7, x=7
2.2 关系运算符
关系运算符用于比较两个值,返回boolean类型结果:
>大于<小于>=大于等于<=小于等于==等于!=不等于
易错点:比较两个对象内容是否相同时,
==比较的是引用地址,应该使用equals()方法。例如字符串比较:
java复制String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2); // false
System.out.println(s1.equals(s2)); // true
2.3 逻辑运算符
逻辑运算符用于组合多个boolean表达式:
&&逻辑与(短路与)||逻辑或(短路或)!逻辑非&非短路与|非短路或^逻辑异或
短路特性示例:
java复制int a = 5;
if (a > 0 || a++ > 0) {
// 由于a>0为true,||右边的表达式不会执行
System.out.println(a); // 输出5
}
2.4 位运算符
位运算符直接操作整数的二进制位:
&按位与|按位或^按位异或~按位取反<<左移>>右移(带符号)>>>无符号右移
实际应用示例——使用位运算实现权限控制:
java复制final int READ = 1; // 0001
final int WRITE = 2; // 0010
final int EXECUTE = 4; // 0100
int userPermission = READ | WRITE; // 0011
boolean canRead = (userPermission & READ) == READ; // true
boolean canExecute = (userPermission & EXECUTE) == EXECUTE; // false
2.5 赋值运算符
基础的赋值运算符是=,Java还提供了复合赋值运算符:
+=、-=、*=、/=、%=&=、|=、^=<<=、>>=、>>>=
复合赋值运算符会自动进行类型转换:
java复制short s = 5;
s = s + 2; // 编译错误,需要强制转换
s += 2; // 正确,复合赋值会自动转换类型
2.6 条件运算符(三目运算符)
语法格式:条件 ? 表达式1 : 表达式2
java复制int score = 75;
String result = score >= 60 ? "及格" : "不及格";
2.7 instanceof运算符
用于检查对象是否是特定类的实例:
java复制Object obj = "hello";
if (obj instanceof String) {
String s = (String) obj;
System.out.println(s.length());
}
3. 运算符优先级详解
当表达式中包含多个运算符时,计算顺序由优先级决定。以下是Java运算符优先级从高到低的完整列表:
()括号 - 最高优先级++--!~+(正)-(负)(type)一元运算符*/%乘除模+-加减<<>>>>>移位<<=>>=instanceof关系==!=等值&按位与^按位异或|按位或&&逻辑与||逻辑或?:三目=+=-=等赋值 - 最低优先级
记忆口诀:单目乘除位关系,逻辑三目后赋值。
4. 表达式类型与类型转换
4.1 表达式类型推断
Java中每个表达式都有确定的类型,编译器会根据操作数和运算符自动推断:
java复制int a = 5;
double b = 3.2;
var c = a * b; // c的类型是double
4.2 自动类型提升
当表达式中包含不同类型时,会自动向范围大的类型提升:
code复制byte → short → int → long → float → double
char ↗
示例:
java复制byte b = 10;
short s = 20;
int i = b + s; // byte和short运算会自动提升为int
4.3 强制类型转换
当需要将大范围类型转换为小范围类型时,需要使用强制转换:
java复制double d = 3.14;
int i = (int) d; // i=3,直接截断小数部分
注意:强制转换可能导致精度丢失或数据溢出:
java复制int big = 200;
byte small = (byte) big; // 溢出,实际值为-56
5. 常见问题与实用技巧
5.1 浮点数比较陷阱
由于浮点数的精度问题,直接使用==比较可能会出错:
java复制double a = 0.1 + 0.2;
double b = 0.3;
System.out.println(a == b); // false!
正确做法是允许一定的误差范围:
java复制final double EPSILON = 1e-10;
System.out.println(Math.abs(a - b) < EPSILON); // true
5.2 字符串连接的特殊性
+运算符在字符串上下文中有特殊行为:
java复制System.out.println(1 + 2 + "3"); // "33"
System.out.println("1" + 2 + 3); // "123"
5.3 利用位运算优化计算
位运算在某些场景下可以大幅提升性能:
java复制// 判断奇偶
boolean isOdd = (num & 1) == 1;
// 交换两个变量的值
a ^= b;
b ^= a;
a ^= b;
// 乘以2的n次方
int result = num << n;
5.4 避免空指针异常
在使用.运算符前应该检查对象是否为null:
java复制String str = possiblyNull();
int length = str != null ? str.length() : 0;
5.5 运算符重载的限制
Java不支持自定义运算符重载,但+对字符串有特殊处理:
java复制public class Point {
private int x, y;
// Java不支持这样的运算符重载
// public Point operator+(Point other) { ... }
}
6. 综合应用案例
6.1 位运算实现权限系统
java复制public class PermissionSystem {
public static final int READ = 1 << 0; // 0001
public static final int WRITE = 1 << 1; // 0010
public static final int EXECUTE = 1 << 2;// 0100
private int permissions;
public void setPermission(int permission, boolean enabled) {
if (enabled) {
permissions |= permission;
} else {
permissions &= ~permission;
}
}
public boolean hasPermission(int permission) {
return (permissions & permission) == permission;
}
public static void main(String[] args) {
PermissionSystem ps = new PermissionSystem();
ps.setPermission(READ, true);
ps.setPermission(WRITE, true);
System.out.println("Can read? " + ps.hasPermission(READ));
System.out.println("Can execute? " + ps.hasPermission(EXECUTE));
}
}
6.2 使用三目运算符简化代码
java复制public String getGrade(int score) {
return score >= 90 ? "A" :
score >= 80 ? "B" :
score >= 70 ? "C" :
score >= 60 ? "D" : "F";
}
6.3 复合赋值运算符的性能优势
java复制// 字符串拼接的性能对比
String result = "";
// 低效写法(每次循环创建新StringBuilder)
for (int i = 0; i < 100; i++) {
result = result + i;
}
// 高效写法(使用复合赋值)
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100; i++) {
sb.append(i);
}
result = sb.toString();
在实际开发中,理解运算符和表达式的细节可以避免很多隐蔽的bug,也能写出更高效、更简洁的代码。建议初学者多动手实践,通过编写测试代码来验证不同运算符的行为特点。