Java运算符与表达式总结整理串讲
#一、运算符概述
#1.1 什么是运算符
#运算符(Operator)是用来对操作数进行运算的符号。Java提供了丰富的运算符,用于执行各种计算和逻辑操作。
1.2 运算符的分类
#Java运算符可以分为以下几类:
- 算术运算符
- 关系运算符(比较运算符)
- 逻辑运算符
- 位运算符
- 赋值运算符
- 条件运算符(三元运算符)
- 其他运算符(instanceof、new等)
二、算术运算符
#2.1 基本算术运算符
#| 运算符 | 名称 | 功能 | 示例 |
|---|
| + | 加法 | 两数相加 | 3 + 5 = 8 |
| - | 减法 | 两数相减 | 10 - 3 = 7 |
| * | 乘法 | 两数相乘 | 4 * 5 = 20 |
| / | 除法 | 两数相除 | 10 / 3 = 3(整数) |
| % | 取模(取余) | 求余数 | 10 % 3 = 1 |
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| public class ArithmeticOperators {
public static void main(String[] args) {
int a = 10;
int b = 3;
System.out.println("a = " + a + ", b = " + b);
System.out.println("a + b = " + (a + b)); // 13
System.out.println("a - b = " + (a - b)); // 7
System.out.println("a * b = " + (a * b)); // 30
System.out.println("a / b = " + (a / b)); // 3(整数除法)
System.out.println("a % b = " + (a % b)); // 1
// 浮点数除法
double x = 10.0;
double y = 3.0;
System.out.println("x / y = " + (x / y)); // 3.3333333333333335
}
}
|
2.2 自增自减运算符
#| 运算符 | 名称 | 功能 | 示例 |
|---|
| ++ | 自增 | 操作数加1 | a++ 或 ++a |
| – | 自减 | 操作数减1 | a-- 或 --a |
前置和后置的区别:
- 前置(++a):先自增,再使用
- 后置(a++):先使用,再自增
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| public class IncrementDecrement {
public static void main(String[] args) {
int a = 5;
// 后置自增
System.out.println("a = " + a); // 5
System.out.println("a++ = " + a++); // 5(先使用,再自增)
System.out.println("a = " + a); // 6
int b = 5;
// 前置自增
System.out.println("b = " + b); // 5
System.out.println("++b = " + ++b); // 6(先自增,再使用)
System.out.println("b = " + b); // 6
// 自减示例
int c = 5;
System.out.println("c-- = " + c--); // 5
System.out.println("c = " + c); // 4
int d = 5;
System.out.println("--d = " + --d); // 4
System.out.println("d = " + d); // 4
}
}
|
2.3 字符串连接运算符
#+ 运算符在操作字符串时,用于连接字符串。
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| public class StringConcatenation {
public static void main(String[] args) {
String str1 = "Hello";
String str2 = "World";
String result = str1 + " " + str2;
System.out.println(result); // Hello World
// 字符串与数字连接
int num = 100;
String str3 = "数字是: " + num;
System.out.println(str3); // 数字是: 100
// 注意运算顺序
System.out.println("结果: " + 10 + 20); // 结果: 1020(字符串连接)
System.out.println("结果: " + (10 + 20)); // 结果: 30(先计算,再连接)
}
}
|
三、关系运算符(比较运算符)
#关系运算符用于比较两个值,返回布尔类型(true或false)。
| 运算符 | 名称 | 功能 | 示例 | 结果 |
|---|
| == | 等于 | 判断两值是否相等 | 5 == 5 | true |
| != | 不等于 | 判断两值是否不相等 | 5 != 3 | true |
| > | 大于 | 判断左值是否大于右值 | 5 > 3 | true |
| < | 小于 | 判断左值是否小于右值 | 5 < 3 | false |
| >= | 大于等于 | 判断左值是否大于等于右值 | 5 >= 5 | true |
| <= | 小于等于 | 判断左值是否小于等于右值 | 5 <= 3 | false |
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| public class RelationalOperators {
public static void main(String[] args) {
int a = 10;
int b = 5;
System.out.println("a = " + a + ", b = " + b);
System.out.println("a == b: " + (a == b)); // false
System.out.println("a != b: " + (a != b)); // true
System.out.println("a > b: " + (a > b)); // true
System.out.println("a < b: " + (a < b)); // false
System.out.println("a >= b: " + (a >= b)); // true
System.out.println("a <= b: " + (a <= b)); // false
// 注意:== 比较的是值(基本类型)或引用(引用类型)
String str1 = "Hello";
String str2 = "Hello";
String str3 = new String("Hello");
System.out.println("str1 == str2: " + (str1 == str2)); // true(字符串常量池)
System.out.println("str1 == str3: " + (str1 == str3)); // false(不同对象)
System.out.println("str1.equals(str3): " + str1.equals(str3)); // true(内容相同)
}
}
|
四、逻辑运算符
#逻辑运算符用于连接布尔表达式,返回布尔值。
4.1 基本逻辑运算符
#| 运算符 | 名称 | 功能 | 示例 | 结果 |
|---|
| && | 逻辑与(短路) | 两个条件都为true才返回true | true && false | false |
| || | 逻辑或(短路) | 至少一个条件为true就返回true | true || false | true |
| ! | 逻辑非 | 取反 | !true | false |
| & | 逻辑与(非短路) | 两个条件都为true才返回true | true & false | false |
| | | 逻辑或(非短路) | 至少一个条件为true就返回true | true | false | true |
| ^ | 逻辑异或 | 两个条件不同时返回true | true ^ false | true |
4.2 短路与非短路的区别
#- 短路运算符(&&、||):如果第一个操作数已经能确定结果,就不再计算第二个操作数
- 非短路运算符(&、|):无论第一个操作数结果如何,都会计算第二个操作数
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| public class LogicalOperators {
public static void main(String[] args) {
boolean a = true;
boolean b = false;
// 基本逻辑运算
System.out.println("a && b: " + (a && b)); // false
System.out.println("a || b: " + (a || b)); // true
System.out.println("!a: " + (!a)); // false
System.out.println("a ^ b: " + (a ^ b)); // true
// 短路与非短路的区别
int x = 5;
int y = 10;
// 短路与:如果第一个为false,不执行第二个
if (x > 10 && y++ > 5) {
// 不会执行
}
System.out.println("y = " + y); // 10(y++未执行)
int z = 10;
// 非短路与:即使第一个为false,也执行第二个
if (x > 10 & z++ > 5) {
// 不会执行
}
System.out.println("z = " + z); // 11(z++已执行)
// 短路或:如果第一个为true,不执行第二个
int m = 5;
int n = 10;
if (m < 10 || n++ > 5) {
// 会执行
}
System.out.println("n = " + n); // 10(n++未执行)
}
}
|
4.3 逻辑运算符真值表
#| A | B | A && B | A || B | !A | A ^ B |
|---|
| true | true | true | true | false | false |
| true | false | false | true | false | true |
| false | true | false | true | true | true |
| false | false | false | false | true | false |
五、位运算符
#位运算符对整数的二进制位进行操作。
| 运算符 | 名称 | 功能 | 示例 |
|---|
| & | 按位与 | 两个位都为1时结果为1 | 5 & 3 = 1 |
| | | 按位或 | 至少一个位为1时结果为1 | 5 | 3 = 7 |
| ^ | 按位异或 | 两个位不同时结果为1 | 5 ^ 3 = 6 |
| ~ | 按位取反 | 0变1,1变0 | ~5 = -6 |
| « | 左移 | 左移指定位数,右边补0 | 5 << 1 = 10 |
| » | 右移 | 右移指定位数,左边补符号位 | -5 >> 1 = -3 |
| »> | 无符号右移 | 右移指定位数,左边补0 | -5 >>> 1 = 2147483645 |
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| public class BitwiseOperators {
public static void main(String[] args) {
int a = 5; // 二进制:0101
int b = 3; // 二进制:0011
System.out.println("a = " + a + " (二进制: " + Integer.toBinaryString(a) + ")");
System.out.println("b = " + b + " (二进制: " + Integer.toBinaryString(b) + ")");
// 按位与
System.out.println("a & b = " + (a & b)); // 1 (0001)
// 按位或
System.out.println("a | b = " + (a | b)); // 7 (0111)
// 按位异或
System.out.println("a ^ b = " + (a ^ b)); // 6 (0110)
// 按位取反
System.out.println("~a = " + (~a)); // -6
// 左移
System.out.println("a << 1 = " + (a << 1)); // 10 (1010)
// 右移
System.out.println("a >> 1 = " + (a >> 1)); // 2 (0010)
// 无符号右移
int c = -5;
System.out.println("c >>> 1 = " + (c >>> 1));
}
}
|
5.1 位运算应用示例
#示例1:判断奇偶数
1
2
3
4
5
6
7
8
9
10
11
| public class BitwiseApplications {
public static void main(String[] args) {
int num = 10;
// 使用位运算判断奇偶:偶数的最低位为0
if ((num & 1) == 0) {
System.out.println(num + " 是偶数");
} else {
System.out.println(num + " 是奇数");
}
}
}
|
示例2:交换两个数(不使用临时变量)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| public class SwapWithoutTemp {
public static void main(String[] args) {
int a = 5;
int b = 10;
System.out.println("交换前: a = " + a + ", b = " + b);
// 使用异或运算交换
a = a ^ b;
b = a ^ b;
a = a ^ b;
System.out.println("交换后: a = " + a + ", b = " + b);
}
}
|
六、赋值运算符
#6.1 基本赋值运算符
#= 是最基本的赋值运算符。
6.2 复合赋值运算符
#复合赋值运算符结合了算术运算和赋值运算。
| 运算符 | 等价于 | 示例 |
|---|
| += | a = a + b | a += 5 等价于 a = a + 5 |
| -= | a = a - b | a -= 5 等价于 a = a - 5 |
| *= | a = a * b | a *= 5 等价于 a = a * 5 |
| /= | a = a / b | a /= 5 等价于 a = a / 5 |
| %= | a = a % b | a %= 5 等价于 a = a % 5 |
| &= | a = a & b | a &= 5 等价于 a = a & 5 |
| |= | a = a | b | a |= 5 等价于 a = a | 5 |
| ^= | a = a ^ b | a ^= 5 等价于 a = a ^ 5 |
| «= | a = a « b | a <<= 1 等价于 a = a << 1 |
| »= | a = a » b | a >>= 1 等价于 a = a >> 1 |
| »>= | a = a »> b | a >>>= 1 等价于 a = a >>> 1 |
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| public class AssignmentOperators {
public static void main(String[] args) {
int a = 10;
a += 5; // a = a + 5 = 15
System.out.println("a += 5: " + a);
a -= 3; // a = a - 3 = 12
System.out.println("a -= 3: " + a);
a *= 2; // a = a * 2 = 24
System.out.println("a *= 2: " + a);
a /= 4; // a = a / 4 = 6
System.out.println("a /= 4: " + a);
a %= 4; // a = a % 4 = 2
System.out.println("a %= 4: " + a);
}
}
|
七、条件运算符(三元运算符)
#条件运算符是Java中唯一的三元运算符,格式为:条件 ? 表达式1 : 表达式2
语法:
1
| result = condition ? valueIfTrue : valueIfFalse;
|
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| public class TernaryOperator {
public static void main(String[] args) {
int a = 10;
int b = 5;
// 找出最大值
int max = (a > b) ? a : b;
System.out.println("最大值: " + max);
// 判断奇偶数
String result = (a % 2 == 0) ? "偶数" : "奇数";
System.out.println(a + " 是 " + result);
// 嵌套使用
int c = 15;
int maxOfThree = (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c);
System.out.println("三个数中的最大值: " + maxOfThree);
}
}
|
八、运算符优先级
#运算符优先级决定了表达式中运算的执行顺序。优先级高的运算符先执行。
8.1 运算符优先级表(从高到低)
#| 优先级 | 运算符 | 结合性 | 说明 |
|---|
| 1 | () [] . | 左→右 | 括号、数组下标、成员访问 |
| 2 | ++ – ! ~ | 右→左 | 自增自减、逻辑非、按位取反 |
| 3 | * / % | 左→右 | 乘除取模 |
| 4 | + - | 左→右 | 加减 |
| 5 | « » »> | 左→右 | 位移运算 |
| 6 | < > <= >= instanceof | 左→右 | 关系运算 |
| 7 | == != | 左→右 | 相等性判断 |
| 8 | & | 左→右 | 按位与 |
| 9 | ^ | 左→右 | 按位异或 |
| 10 | | | 左→右 | 按位或 |
| 11 | && | 左→右 | 逻辑与 |
| 12 | || | 左→右 | 逻辑或 |
| 13 | ? : | 右→左 | 三元运算符 |
| 14 | = += -= *= /= %= 等 | 右→左 | 赋值运算符 |
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| public class OperatorPrecedence {
public static void main(String[] args) {
int a = 5;
int b = 3;
int c = 2;
// 注意运算符优先级
int result1 = a + b * c; // 先算乘法,再算加法:5 + 6 = 11
System.out.println("a + b * c = " + result1);
int result2 = (a + b) * c; // 先算括号,再算乘法:8 * 2 = 16
System.out.println("(a + b) * c = " + result2);
boolean result3 = a > b && b > c; // 先算关系运算,再算逻辑与
System.out.println("a > b && b > c = " + result3);
int result4 = a++ + ++b; // 先算++b,再算a++,最后相加
System.out.println("a++ + ++b = " + result4);
System.out.println("a = " + a + ", b = " + b);
}
}
|
九、表达式
#9.1 什么是表达式
#表达式(Expression)是由运算符、操作数和括号组成的,可以计算出一个值的式子。
表达式的特点:
- 表达式有值
- 表达式可以嵌套
- 表达式的结果类型由运算符和操作数决定
9.2 表达式类型
#| 表达式类型 | 说明 | 示例 |
|---|
| 算术表达式 | 使用算术运算符 | a + b * c |
| 关系表达式 | 使用关系运算符,返回boolean | a > b |
| 逻辑表达式 | 使用逻辑运算符,返回boolean | a > b && c < d |
| 赋值表达式 | 使用赋值运算符 | a = b + c |
| 条件表达式 | 使用三元运算符 | a > b ? a : b |
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| public class Expressions {
public static void main(String[] args) {
int a = 10;
int b = 5;
int c = 3;
// 算术表达式
int result1 = a + b * c;
System.out.println("算术表达式: " + result1);
// 关系表达式
boolean result2 = a > b && b > c;
System.out.println("关系表达式: " + result2);
// 逻辑表达式
boolean result3 = (a > b) || (c > a);
System.out.println("逻辑表达式: " + result3);
// 赋值表达式
int result4 = a += b; // a = a + b,然后返回a的值
System.out.println("赋值表达式: " + result4);
// 条件表达式
int result5 = a > b ? a : b;
System.out.println("条件表达式: " + result5);
// 复合表达式
int result6 = (a + b) * (c - 1) + (a % b);
System.out.println("复合表达式: " + result6);
}
}
|
十、练习题
#练习题1:算术运算符
#请分析以下代码的输出结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
| public class Exercise1 {
public static void main(String[] args) {
int a = 10;
int b = 3;
System.out.println(a / b);
System.out.println(a % b);
System.out.println(a++);
System.out.println(++a);
System.out.println(b--);
System.out.println(--b);
}
}
|
参考答案:
1
2
3
4
5
6
| 3
1
10
12
3
1
|
练习题2:关系运算符
#请编写代码,判断一个年份是否为闰年。
闰年条件:能被4整除但不能被100整除,或者能被400整除。
参考答案:
1
2
3
4
5
6
7
8
9
10
11
12
13
| public class Exercise2 {
public static void main(String[] args) {
int year = 2024;
boolean isLeapYear = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
if (isLeapYear) {
System.out.println(year + " 是闰年");
} else {
System.out.println(year + " 不是闰年");
}
}
}
|
练习题3:逻辑运算符
#请分析以下代码的输出结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| public class Exercise3 {
public static void main(String[] args) {
int x = 5;
int y = 10;
int z = 15;
boolean result1 = x > 3 && y < 20;
boolean result2 = x > 10 || y < 5;
boolean result3 = !(x > 10);
boolean result4 = x > 3 && y < 5 || z > 10;
System.out.println("result1: " + result1);
System.out.println("result2: " + result2);
System.out.println("result3: " + result3);
System.out.println("result4: " + result4);
}
}
|
参考答案:
1
2
3
4
| result1: true
result2: false
result3: true
result4: true
|
练习题4:位运算符
#请编写代码实现以下功能:
- 使用位运算判断一个数是否为2的幂
- 使用位运算计算两个数的最大公约数(简化版)
参考答案:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| public class Exercise4 {
public static void main(String[] args) {
// 1. 判断是否为2的幂
int num = 16;
// 2的幂的二进制表示只有一个1,如:16 = 10000
// num & (num - 1) 如果为0,说明是2的幂
boolean isPowerOfTwo = (num > 0) && ((num & (num - 1)) == 0);
System.out.println(num + " 是2的幂? " + isPowerOfTwo);
// 2. 使用位运算交换两个数
int a = 5;
int b = 10;
System.out.println("交换前: a = " + a + ", b = " + b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
System.out.println("交换后: a = " + a + ", b = " + b);
}
}
|
练习题5:运算符优先级
#请分析以下表达式的值,并说明计算过程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| public class Exercise5 {
public static void main(String[] args) {
int a = 5;
int b = 3;
int c = 2;
int result1 = a + b * c;
int result2 = (a + b) * c;
int result3 = a++ + ++b * c;
boolean result4 = a > b && b > c || a < c;
System.out.println("result1: " + result1);
System.out.println("result2: " + result2);
System.out.println("result3: " + result3);
System.out.println("result4: " + result4);
}
}
|
参考答案:
1
2
3
4
| result1: 11 (5 + 3 * 2 = 5 + 6 = 11)
result2: 16 ((5 + 3) * 2 = 8 * 2 = 16)
result3: 14 (5 + 4 * 2 = 5 + 8 = 13, 但a++后a=6, b=4)
result4: true ((6 > 4 && 4 > 2) || (6 < 2) = (true && true) || false = true)
|
练习题6:综合应用
#请编写一个程序,实现以下功能:
- 输入三个数,使用三元运算符找出最大值
- 判断这三个数能否构成三角形(任意两边之和大于第三边)
- 如果构成三角形,判断是等边、等腰还是普通三角形
参考答案:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| public class Exercise6 {
public static void main(String[] args) {
int a = 5;
int b = 5;
int c = 5;
// 1. 找出最大值
int max = (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c);
System.out.println("最大值: " + max);
// 2. 判断能否构成三角形
boolean canFormTriangle = (a + b > c) && (a + c > b) && (b + c > a);
if (canFormTriangle) {
System.out.println("可以构成三角形");
// 3. 判断三角形类型
if (a == b && b == c) {
System.out.println("等边三角形");
} else if (a == b || a == c || b == c) {
System.out.println("等腰三角形");
} else {
System.out.println("普通三角形");
}
} else {
System.out.println("不能构成三角形");
}
}
}
|
十一、运算符与表达式对比分析表
#11.1 算术运算符对比
#| 运算符 | 功能 | 操作数类型 | 结果类型 | 注意事项 |
|---|
| + | 加法/字符串连接 | 数值/字符串 | 数值/字符串 | 字符串+数字会转换为字符串 |
| - | 减法 | 数值 | 数值 | 只能用于数值类型 |
| * | 乘法 | 数值 | 数值 | 注意溢出问题 |
| / | 除法 | 数值 | 数值 | 整数除法会截断小数部分 |
| % | 取模 | 数值 | 数值 | 结果的符号与被除数相同 |
| ++ | 自增 | 数值 | 数值 | 前置和后置的区别 |
| – | 自减 | 数值 | 数值 | 前置和后置的区别 |
11.2 关系运算符对比
#| 运算符 | 功能 | 操作数类型 | 结果类型 | 注意事项 |
|---|
| == | 等于 | 任意 | boolean | 基本类型比较值,引用类型比较引用 |
| != | 不等于 | 任意 | boolean | 基本类型比较值,引用类型比较引用 |
| > | 大于 | 数值 | boolean | 只能用于数值类型 |
| < | 小于 | 数值 | boolean | 只能用于数值类型 |
| >= | 大于等于 | 数值 | boolean | 只能用于数值类型 |
| <= | 小于等于 | 数值 | boolean | 只能用于数值类型 |
11.3 逻辑运算符对比
#| 运算符 | 名称 | 短路特性 | 使用场景 | 性能 |
|---|
| && | 逻辑与(短路) | 是 | 常用,推荐 | 更好(可能提前结束) |
| || | 逻辑或(短路) | 是 | 常用,推荐 | 更好(可能提前结束) |
| ! | 逻辑非 | 无 | 取反操作 | 无影响 |
| & | 逻辑与(非短路) | 否 | 需要计算所有条件 | 较差 |
| | | 逻辑或(非短路) | 否 | 需要计算所有条件 | 较差 |
| ^ | 逻辑异或 | 否 | 判断两个条件不同 | 无影响 |
11.4 位运算符对比
#| 运算符 | 功能 | 操作数类型 | 结果类型 | 应用场景 |
|---|
| & | 按位与 | 整数 | 整数 | 掩码操作、判断奇偶 |
| | | 按位或 | 整数 | 整数 | 设置特定位 |
| ^ | 按位异或 | 整数 | 整数 | 交换变量、加密 |
| ~ | 按位取反 | 整数 | 整数 | 取反操作 |
| « | 左移 | 整数 | 整数 | 快速乘以2的幂 |
| » | 右移 | 整数 | 整数 | 快速除以2的幂(有符号) |
| »> | 无符号右移 | 整数 | 整数 | 快速除以2的幂(无符号) |
11.5 赋值运算符对比
#| 运算符 | 等价表达式 | 使用场景 | 性能 |
|---|
| = | a = b | 基本赋值 | 标准 |
| += | a = a + b | 累加操作 | 相同 |
| -= | a = a - b | 递减操作 | 相同 |
| *= | a = a * b | 累乘操作 | 相同 |
| /= | a = a / b | 除法赋值 | 相同 |
| %= | a = a % b | 取模赋值 | 相同 |
| &= | a = a & b | 位与赋值 | 相同 |
| |= | a = a | b | 位或赋值 | 相同 |
| ^= | a = a ^ b | 位异或赋值 | 相同 |
| «= | a = a « b | 左移赋值 | 相同 |
| »= | a = a » b | 右移赋值 | 相同 |
| »>= | a = a »> b | 无符号右移赋值 | 相同 |
11.6 运算符优先级总结
#| 优先级 | 运算符类别 | 运算符 | 结合性 |
|---|
| 最高 | 括号、访问 | () [] . | 左→右 |
| 高 | 单目运算符 | ++ – ! ~ | 右→左 |
| 中高 | 乘除取模 | * / % | 左→右 |
| 中 | 加减 | + - | 左→右 |
| 中低 | 位移 | « » »> | 左→右 |
| 低 | 关系 | < > <= >= | 左→右 |
| 低 | 相等 | == != | 左→右 |
| 低 | 位运算 | & ^ | | 左→右 |
| 低 | 逻辑 | && || | 左→右 |
| 最低 | 条件、赋值 | ? : = += 等 | 右→左 |
11.7 表达式类型对比
#| 表达式类型 | 运算符 | 结果类型 | 典型应用 |
|---|
| 算术表达式 | + - * / % | 数值 | 数学计算 |
| 关系表达式 | == != > < >= <= | boolean | 条件判断 |
| 逻辑表达式 | && || ! | boolean | 复合条件 |
| 位运算表达式 | & | ^ ~ « » | 整数 | 位操作、优化 |
| 赋值表达式 | = += -= 等 | 赋值类型 | 变量赋值 |
| 条件表达式 | ? : | 表达式类型 | 条件选择 |
十二、拓展:正则表达式
#12.1 什么是正则表达式
#正则表达式(Regular Expression,简称Regex)是一种用来描述字符串模式的工具,可以用来匹配、查找、替换字符串。
12.2 Java中的正则表达式
#Java中使用java.util.regex包来处理正则表达式,主要包含两个类:
- Pattern:编译正则表达式
- Matcher:执行匹配操作
12.3 基本语法
#字符类
#| 表达式 | 说明 | 示例 |
|---|
. | 匹配除换行符外的任意字符 | a.c 匹配 “abc”、“a1c” |
[abc] | 匹配a、b或c中的任意一个 | [abc] 匹配 “a”、“b”、“c” |
[^abc] | 匹配除a、b、c外的任意字符 | [^abc] 匹配 “d”、“1” |
[a-z] | 匹配a到z的任意小写字母 | [a-z] 匹配 “a”、“b”、“z” |
[A-Z] | 匹配A到Z的任意大写字母 | [A-Z] 匹配 “A”、“B”、“Z” |
[0-9] | 匹配0到9的任意数字 | [0-9] 匹配 “0”、“5”、“9” |
\d | 匹配数字,等价于[0-9] | \d 匹配 “0”、“9” |
\D | 匹配非数字,等价于[^0-9] | \D 匹配 “a”、"@" |
\w | 匹配单词字符(字母、数字、下划线) | \w 匹配 “a”、“1”、"_" |
\W | 匹配非单词字符 | \W 匹配 “@"、” " |
\s | 匹配空白字符(空格、制表符等) | \s 匹配 " “、"\t” |
\S | 匹配非空白字符 | \S 匹配 “a”、“1” |
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class RegexBasic {
public static void main(String[] args) {
String text = "Hello World 123";
// 匹配数字
Pattern pattern1 = Pattern.compile("\\d");
Matcher matcher1 = pattern1.matcher(text);
System.out.println("数字:");
while (matcher1.find()) {
System.out.print(matcher1.group() + " ");
}
System.out.println();
// 匹配字母
Pattern pattern2 = Pattern.compile("[a-zA-Z]");
Matcher matcher2 = pattern2.matcher(text);
System.out.println("字母:");
while (matcher2.find()) {
System.out.print(matcher2.group() + " ");
}
System.out.println();
}
}
|
| 表达式 | 说明 | 示例 |
|---|
* | 匹配0次或多次 | a* 匹配 “"、“a”、“aa” |
+ | 匹配1次或多次 | a+ 匹配 “a”、“aa” |
? | 匹配0次或1次 | a? 匹配 “"、“a” |
{n} | 匹配恰好n次 | a{3} 匹配 “aaa” |
{n,} | 匹配至少n次 | a{2,} 匹配 “aa”、“aaa” |
{n,m} | 匹配n到m次 | a{2,4} 匹配 “aa”、“aaa”、“aaaa” |
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class RegexQuantifiers {
public static void main(String[] args) {
String[] texts = {"a", "aa", "aaa", "aaaa", "b"};
Pattern pattern = Pattern.compile("a{2,3}"); // 匹配2到3个a
for (String text : texts) {
Matcher matcher = pattern.matcher(text);
System.out.println(text + " 匹配: " + matcher.matches());
}
}
}
|
边界匹配
#| 表达式 | 说明 | 示例 |
|---|
^ | 匹配字符串开始 | ^Hello 匹配以"Hello"开头的字符串 |
$ | 匹配字符串结束 | World$ 匹配以"World"结尾的字符串 |
\b | 匹配单词边界 | \bword\b 匹配独立的"word” |
\B | 匹配非单词边界 | \Bword\B 匹配非独立的"word” |
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class RegexBoundaries {
public static void main(String[] args) {
String text = "Hello World Hello";
// 匹配以Hello开头的字符串
Pattern pattern1 = Pattern.compile("^Hello");
Matcher matcher1 = pattern1.matcher(text);
System.out.println("以Hello开头: " + matcher1.find());
// 匹配单词边界
Pattern pattern2 = Pattern.compile("\\bHello\\b");
Matcher matcher2 = pattern2.matcher(text);
int count = 0;
while (matcher2.find()) {
count++;
}
System.out.println("单词Hello出现次数: " + count);
}
}
|
分组和引用
#| 表达式 | 说明 | 示例 |
|---|
() | 分组 | (ab)+ 匹配 “ab”、“abab” |
| | 或 | a|b 匹配 “a"或"b” |
\1 | 引用第一个分组 | (a)\1 匹配 “aa” |
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class RegexGroups {
public static void main(String[] args) {
String text = "2024-01-15";
Pattern pattern = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
Matcher matcher = pattern.matcher(text);
if (matcher.matches()) {
System.out.println("完整匹配: " + matcher.group(0));
System.out.println("年份: " + matcher.group(1));
System.out.println("月份: " + matcher.group(2));
System.out.println("日期: " + matcher.group(3));
}
}
}
|
12.4 String类中的正则表达式方法
#matches() - 判断是否匹配
#1
2
3
| String str = "12345";
boolean matches = str.matches("\\d+"); // 判断是否全为数字
System.out.println(matches); // true
|
split() - 分割字符串
#1
2
3
4
5
| String str = "apple,banana,orange";
String[] fruits = str.split(",");
for (String fruit : fruits) {
System.out.println(fruit);
}
|
replaceAll() - 替换所有匹配
#1
2
3
| String str = "Hello123World456";
String result = str.replaceAll("\\d+", "数字");
System.out.println(result); // Hello数字World数字
|
replaceFirst() - 替换第一个匹配
#1
2
3
| String str = "Hello123World456";
String result = str.replaceFirst("\\d+", "数字");
System.out.println(result); // Hello数字World456
|
综合示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| public class StringRegexMethods {
public static void main(String[] args) {
// 1. matches() - 验证邮箱格式
String email = "user@example.com";
boolean isValidEmail = email.matches("[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}");
System.out.println("邮箱格式正确? " + isValidEmail);
// 2. split() - 分割字符串
String text = "apple,banana,orange";
String[] fruits = text.split(",");
System.out.println("分割结果:");
for (String fruit : fruits) {
System.out.println(fruit);
}
// 3. replaceAll() - 替换所有数字
String str1 = "价格是100元,折扣是20%";
String result1 = str1.replaceAll("\\d+", "X");
System.out.println("替换后: " + result1);
// 4. replaceFirst() - 替换第一个数字
String str2 = "价格是100元,折扣是20%";
String result2 = str2.replaceFirst("\\d+", "X");
System.out.println("替换后: " + result2);
}
}
|
12.5 常用正则表达式示例
#验证手机号
# 1
2
3
4
5
6
7
8
9
10
11
| public class PhoneValidation {
public static void main(String[] args) {
String[] phones = {"13812345678", "15912345678", "12345678901", "1381234"};
String regex = "1[3-9]\\d{9}"; // 1开头,第二位3-9,后面9位数字
for (String phone : phones) {
boolean isValid = phone.matches(regex);
System.out.println(phone + " 是否有效: " + isValid);
}
}
}
|
验证邮箱
# 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| public class EmailValidation {
public static void main(String[] args) {
String[] emails = {
"user@example.com",
"test.email@domain.co.uk",
"invalid.email",
"@domain.com"
};
String regex = "[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}";
for (String email : emails) {
boolean isValid = email.matches(regex);
System.out.println(email + " 是否有效: " + isValid);
}
}
}
|
验证身份证号
# 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| public class IDCardValidation {
public static void main(String[] args) {
String[] idCards = {
"110101199001011234",
"11010119900101123X",
"12345678901234567",
"11010119900101123"
};
String regex = "\\d{17}[\\dXx]"; // 18位,最后一位可以是数字或X
for (String idCard : idCards) {
boolean isValid = idCard.matches(regex);
System.out.println(idCard + " 是否有效: " + isValid);
}
}
}
|
提取数字
# 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class ExtractNumbers {
public static void main(String[] args) {
String text = "价格是100元,折扣是20%,总共120元";
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher(text);
System.out.println("提取的数字:");
while (matcher.find()) {
System.out.println(matcher.group());
}
}
}
|
十三、正则表达式练习题
#练习题1:基本匹配
#请编写代码,使用正则表达式匹配以下内容:
- 匹配所有数字
- 匹配所有字母
- 匹配所有单词(连续的字母)
参考答案:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class RegexExercise1 {
public static void main(String[] args) {
String text = "Hello123World456";
// 1. 匹配所有数字
Pattern pattern1 = Pattern.compile("\\d+");
Matcher matcher1 = pattern1.matcher(text);
System.out.println("数字:");
while (matcher1.find()) {
System.out.print(matcher1.group() + " ");
}
System.out.println();
// 2. 匹配所有字母
Pattern pattern2 = Pattern.compile("[a-zA-Z]");
Matcher matcher2 = pattern2.matcher(text);
System.out.println("字母:");
while (matcher2.find()) {
System.out.print(matcher2.group() + " ");
}
System.out.println();
// 3. 匹配所有单词
Pattern pattern3 = Pattern.compile("[a-zA-Z]+");
Matcher matcher3 = pattern3.matcher(text);
System.out.println("单词:");
while (matcher3.find()) {
System.out.print(matcher3.group() + " ");
}
}
}
|
练习题2:验证格式
#请编写代码验证以下格式:
- 验证手机号(11位,1开头)
- 验证邮箱(简单格式)
- 验证日期格式(YYYY-MM-DD)
参考答案:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| public class RegexExercise2 {
public static void main(String[] args) {
// 1. 验证手机号
String[] phones = {"13812345678", "12345678901", "1381234"};
String phoneRegex = "1[3-9]\\d{9}";
System.out.println("手机号验证:");
for (String phone : phones) {
System.out.println(phone + ": " + phone.matches(phoneRegex));
}
// 2. 验证邮箱
String[] emails = {"user@example.com", "invalid.email", "test@domain"};
String emailRegex = "[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}";
System.out.println("\n邮箱验证:");
for (String email : emails) {
System.out.println(email + ": " + email.matches(emailRegex));
}
// 3. 验证日期
String[] dates = {"2024-01-15", "2024-13-01", "24-01-15"};
String dateRegex = "\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])";
System.out.println("\n日期验证:");
for (String date : dates) {
System.out.println(date + ": " + date.matches(dateRegex));
}
}
}
|
练习题3:字符串替换
#请使用正则表达式实现以下功能:
- 将字符串中的所有数字替换为"*"
- 将字符串中的多个连续空格替换为单个空格
- 提取字符串中的所有邮箱地址
参考答案:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class RegexExercise3 {
public static void main(String[] args) {
// 1. 替换所有数字
String text1 = "价格是100元,折扣是20%";
String result1 = text1.replaceAll("\\d+", "*");
System.out.println("替换数字: " + result1);
// 2. 替换多个空格为单个空格
String text2 = "Hello World Java";
String result2 = text2.replaceAll("\\s+", " ");
System.out.println("替换空格: " + result2);
// 3. 提取邮箱
String text3 = "联系邮箱:user1@example.com 或 user2@test.org";
Pattern pattern = Pattern.compile("[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}");
Matcher matcher = pattern.matcher(text3);
System.out.println("提取的邮箱:");
while (matcher.find()) {
System.out.println(matcher.group());
}
}
}
|
练习题4:分组提取
#请编写代码,从字符串"2024-01-15"中提取年、月、日。
参考答案:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class RegexExercise4 {
public static void main(String[] args) {
String date = "2024-01-15";
Pattern pattern = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
Matcher matcher = pattern.matcher(date);
if (matcher.matches()) {
System.out.println("年份: " + matcher.group(1));
System.out.println("月份: " + matcher.group(2));
System.out.println("日期: " + matcher.group(3));
}
}
}
|
练习题5:综合应用
#请编写一个程序,实现以下功能:
- 验证输入的字符串是否为有效的IP地址(IPv4)
- 从文本中提取所有的URL链接
- 验证密码强度(至少8位,包含大小写字母、数字和特殊字符)
参考答案:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class RegexExercise5 {
public static void main(String[] args) {
// 1. 验证IP地址
String[] ips = {"192.168.1.1", "256.1.1.1", "192.168.1"};
String ipRegex = "((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)";
System.out.println("IP地址验证:");
for (String ip : ips) {
System.out.println(ip + ": " + ip.matches(ipRegex));
}
// 2. 提取URL
String text = "访问 https://www.example.com 或 http://test.org";
Pattern urlPattern = Pattern.compile("https?://[\\w.-]+(?:/[\\w.-]*)*");
Matcher urlMatcher = urlPattern.matcher(text);
System.out.println("\n提取的URL:");
while (urlMatcher.find()) {
System.out.println(urlMatcher.group());
}
// 3. 验证密码强度
String[] passwords = {"Abc123!@", "weak", "Strong123", "Strong123!"};
// 至少8位,包含大小写字母、数字和特殊字符
String passwordRegex = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$";
System.out.println("\n密码强度验证:");
for (String password : passwords) {
System.out.println(password + ": " + password.matches(passwordRegex));
}
}
}
|
十四、正则表达式对比分析表
#14.1 字符类对比
#| 表达式 | 等价表达式 | 说明 | 使用场景 |
|---|
. | - | 任意字符(除换行) | 匹配任意字符 |
\d | [0-9] | 数字 | 匹配数字 |
\D | [^0-9] | 非数字 | 排除数字 |
\w | [a-zA-Z0-9_] | 单词字符 | 匹配字母数字下划线 |
\W | [^a-zA-Z0-9_] | 非单词字符 | 排除单词字符 |
\s | [ \t\n\r\f] | 空白字符 | 匹配空格、制表符等 |
\S | [^ \t\n\r\f] | 非空白字符 | 排除空白字符 |
14.2 量词对比
#| 量词 | 含义 | 贪婪性 | 示例匹配 |
|---|
* | 0次或多次 | 贪婪 | a* 匹配 “aaa” 中的 “aaa” |
*? | 0次或多次 | 非贪婪 | a*? 匹配 “aaa” 中的 "" |
+ | 1次或多次 | 贪婪 | a+ 匹配 “aaa” 中的 “aaa” |
+? | 1次或多次 | 非贪婪 | a+? 匹配 “aaa” 中的 “a” |
? | 0次或1次 | 贪婪 | a? 匹配 “a” 中的 “a” |
?? | 0次或1次 | 非贪婪 | a?? 匹配 “a” 中的 "" |
{n} | 恰好n次 | 固定 | a{3} 匹配 “aaa” |
{n,} | 至少n次 | 贪婪 | a{2,} 匹配 “aaa” 中的 “aaa” |
{n,m} | n到m次 | 贪婪 | a{2,3} 匹配 “aaa” 中的 “aaa” |
14.3 Java正则表达式方法对比
#| 方法 | 类 | 功能 | 返回值 | 使用场景 |
|---|
| matches() | String | 判断整个字符串是否匹配 | boolean | 格式验证 |
| find() | Matcher | 查找下一个匹配 | boolean | 查找所有匹配 |
| group() | Matcher | 获取匹配的字符串 | String | 提取匹配内容 |
| replaceAll() | String | 替换所有匹配 | String | 批量替换 |
| replaceFirst() | String | 替换第一个匹配 | String | 单次替换 |
| split() | String | 按正则分割字符串 | String[] | 字符串分割 |
14.4 Pattern和Matcher使用对比
#| 操作 | Pattern方式 | String方式 | 性能 | 灵活性 |
|---|
| 单次匹配 | Pattern.compile(regex).matcher(str).matches() | str.matches(regex) | String更快 | 相同 |
| 多次匹配 | 编译一次,多次使用 | 每次重新编译 | Pattern更快 | Pattern更灵活 |
| 查找所有 | 使用Matcher.find() | 无直接方法 | Pattern | Pattern |
| 分组提取 | 使用Matcher.group() | 无直接方法 | Pattern | Pattern |
| 替换 | 使用Matcher.replaceAll() | String.replaceAll() | 相近 | 相同 |
14.5 常用正则表达式模式
#| 用途 | 正则表达式 | 说明 |
|---|
| 手机号 | 1[3-9]\d{9} | 1开头,第二位3-9,共11位 |
| 邮箱 | [\w.-]+@[\w.-]+\.[a-zA-Z]{2,} | 简单邮箱格式 |
| 身份证 | \d{17}[\dXx] | 18位身份证号 |
| 日期 | \d{4}-\d{2}-\d{2} | YYYY-MM-DD格式 |
| IP地址 | ((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?) | IPv4地址 |
| URL | https?://[\w.-]+(?:/[\w.-]*)* | HTTP/HTTPS URL |
| 中文 | [\u4e00-\u9fa5]+ | 中文字符 |
| 密码强度 | ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$ | 至少8位,包含大小写、数字、特殊字符 |
14.6 正则表达式性能优化建议
#| 优化建议 | 说明 | 示例 |
|---|
| 预编译Pattern | 多次使用时编译一次 | Pattern pattern = Pattern.compile(regex); |
| 使用非贪婪量词 | 避免过度匹配 | .*? 代替 .* |
| 使用字符类 | 比选择符更高效 | [abc] 代替 (a|b|c) |
| 避免回溯 | 使用原子组或占有量词 | (?>...) 或 ++ |
| 简化表达式 | 避免过度复杂 | 简单表达式更高效 |
| 使用边界 | 限制匹配范围 | \bword\b 代替 word |