#5
45.hutool
工具类库
:比如前面学的网络编程和IO 可以被简单封装为 hutool-socket 使用 例 AIO NIO BIO
模块 |
介绍 |
hutool-aop |
JDK动态代理封装,提供非IOC下的切面支持 |
hutool-bloomFilter |
布隆过滤,提供一些Hash算法的布隆过滤 |
hutool-cache |
简单缓存实现 |
hutool-core |
核心,包括Bean操 作、日期、各种Util等 |
hutool-cron |
定时任务模块,提供类Crontab表达式的定时任务 |
hutool-crypto |
加密解密模块,提供对称、非对称和摘要算法封装 |
hutool-db |
JDBC封装后的数据操作,基于ActiveRecord思想 |
hutool-dfa |
基于DFA模型的多关键字查找 |
hutool-extra |
扩展模块,对第三方封装(模板引擎、邮件、Servlet、二维码、Emoji、FTP、分词等) |
hutool-http |
基于HttpUrlConnection的Http客户端封装 |
hutool-log |
自动识别日志实现的日志门面 |
hutool-script |
脚本执行封装,例如Javascript |
hutool-setting |
功能更强大的Setting配置文件和Properties封装 |
hutool-system |
系统参数调用封装(JVM信息等) |
hutool-json |
JSON实现 |
hutool-captcha |
图片验证码实现 |
hutool-poi |
针对POI中Excel和Word的封装 |
hutool-socket |
基于Java的NIO和AIO的Socket封装 |
hutool-jwt |
JSON Web Token (JWT)封装实现 |
### Hutool工具类详解
#### 一、Hutool简介
**Hutool** 是一个 **Java 工具类库**,旨在通过封装常用功能代码,简化开发流程,提高开发效率。它涵盖了字符串处理、集合操作、IO流、加密解密、日期时间、反射机制等多个领域的工具类,具有 **轻量级、文档齐全、易上手** 的特点,被广泛应用于企业级项目和开源项目中。
#### 二、核心功能模块
Hutool按功能划分为多个模块,以下是主要模块的介绍:
##### 1. 基础工具类(core)
- **字符串处理(StrUtil)**
提供字符串判空、拼接、截取、转换(如驼峰转下划线)、编码解码(Base64、URL等)等功能。
**示例**:
```java
String str = " Hello, Hutool! ";
StrUtil.trim(str); // 去除首尾空格,结果:"Hello, Hutool!"
StrUtil.format("{}是{}工具类", "Hutool", "Java"); // 格式化字符串,结果:"Hutool是Java工具类"
```
- **集合工具(CollUtil)**
简化集合操作,如判空、转换(数组转集合、集合转Map)、过滤、洗牌等。
**示例**:
```java
List<String> list = CollUtil.newArrayList("a", "b", "c");
CollUtil.shuffle(list); // 打乱集合顺序
Map<String, Integer> map = CollUtil.toMap(list, s -> s.length()); // 集合转Map
```
- **数组工具(ArrayUtil)**
支持数组判空、复制、拼接、反转、排序等操作。
**示例**:
```java
int[] arr = {1, 3, 2};
ArrayUtil.sort(arr); // 排序后:[1, 2, 3]
int[] newArr = ArrayUtil.addAll(arr, 4, 5); // 拼接数组:[1, 2, 3, 4, 5]
```
##### 2. 日期与时间(date-time)
- **DateUtil**
提供日期格式化、加减、比较、时区转换等功能,支持JDK 8+的`LocalDateTime`。
**示例**:
```java
// 当前时间转指定格式
String now = DateUtil.format(DateUtil.now(), "yyyy-MM-dd HH:mm:ss"); // 结果如:"2025-05-22 14:30:00"
// 计算两天后的日期
Date future = DateUtil.offsetDay(new Date(), 2);
```
##### 3. 文件与IO(io)
- **FileUtil**
封装文件操作,如创建/删除文件、读取/写入内容、遍历目录、文件压缩(ZIP/TAR)等。
**示例**:
```java
// 读取文件内容为字符串
String content = FileUtil.readUtf8String("path/to/file.txt");
// 写入内容到文件(自动创建父目录)
FileUtil.writeUtf8String("Hello, Hutool!", "path/to/new_file.txt");
```
- **IOUtil**
处理流操作,如关闭流、流复制、读取类路径资源等。
**示例**:
```java
// 复制输入流到输出流并自动关闭
IOUtil.copy(inputStream, outputStream);
```
##### 4. 加密与安全(crypto)
- **加密工具(如DigestUtil、SecureUtil)**
支持MD5、SHA、AES、RSA等加密算法,简化加密流程。
**示例**:
```java
// MD5加密
String md5 = DigestUtil.md5Hex("password");
// AES加密
AES aes = SecureUtil.aes("密钥".getBytes());
String encryptStr = aes.encryptBase64("明文内容");
```
##### 5. 反射与类操作(reflect)
- **ReflectUtil**
简化反射调用,如创建对象、调用方法、获取字段等,支持泛型和注解处理。
**示例**:
```java
// 实例化对象(无需手动处理异常)
User user = ReflectUtil.newInstance(User.class);
// 调用方法
ReflectUtil.invoke(user, "setName", "张三");
```
##### 6. 网络工具(network)
- **HttpUtil**
封装HTTP请求,支持GET/POST请求、表单提交、JSON参数、文件上传等。
**示例**:
```java
// 发送GET请求
String result = HttpUtil.get("https://api.example.com/data");
// 发送POST请求(JSON参数)
String json = HttpUtil.post("https://api.example.com/submit", "{\"key\":\"value\"}");
```
##### 7. 其他常用模块
- **数学工具(NumberUtil)**:数值转换、进制转换、随机数生成等。
- **正则工具(RegexUtil)**:正则表达式匹配、替换、分组提取等。
- **系统工具(SystemUtil)**:获取系统信息(如内存、CPU、操作系统)、执行命令等。
#### 三、Hutool的优势
1. **简化代码**:避免重复编写基础功能代码,如字符串处理、集合操作等。
2. **一致性**:所有工具类命名规范统一(如`XXXUtil`),方法名直观易读。
3. **健壮性**:内部处理了空指针、非法参数等常见异常,降低代码崩溃风险。
4. **集成方便**:通过Maven或Gradle引入依赖即可使用,无需复杂配置。
**Maven依赖**:
```xml
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.21</version> <!-- 最新版本请查看官网 -->
</dependency>
```
#### 四、使用场景
- **日常开发**:处理字符串、日期、文件等基础需求。
- **工具类开发**:基于Hutool封装更复杂的业务工具。
- **快速原型**:在测试或Demo开发中快速实现功能。
- **开源项目**:许多知名开源项目(如Dromara的Hmily)依赖Hutool提升开发效率。
#### 五、学习资源
- **官方文档**:[Hutool官网](https://hutool.cn/docs/)(提供详细API说明和示例)。
- **GitHub仓库**:[Hutool GitHub](https://github.com/dromara/hutool)(源码与Issue参考)。
- **中文社区**:QQ群、Gitter等渠道交流使用问题。
#### 六、注意事项
- **模块选择**:若无需全部功能,可引入单一模块(如`hutool-core`、`hutool-io`)以减少包体积。
- **版本兼容性**:高版本Hutool可能不兼容低版本JDK(建议使用JDK 8+)。
- **性能考量**:工具类虽便捷,但在高并发场景下需注意底层实现是否满足性能要求。
通过Hutool,开发者可将更多精力聚焦于业务逻辑,而非重复造轮子。无论是新手还是资深工程师,熟练使用Hutool都能显著提升开发效率。
46.SOCKET
使用Java进行TCP编程时,需要使用Socket模型:教程
- 服务器端用
ServerSocket
监听指定端口;
- 客户端使用
Socket(InetAddress, port)
连接服务器;
- 服务器端用
accept()
接收连接并返回Socket
;
- 双方通过
Socket
打开InputStream
/OutputStream
读写数据;
- 服务器端通常使用多线程同时处理多个客户端连接,利用线程池可大幅提升效率;
flush()
用于强制输出缓冲区到网络。
通信方式 |
特点 |
适用场景 |
Socket |
底层网络接口,灵活但需自行处理细节 |
自定义协议、高性能需求 |
HTTP |
基于请求 - 响应,无状态 |
网页浏览、RESTful API |
RPC |
远程过程调用,屏蔽网络细节 |
微服务内部通信(如 gRPC、Dubbo) |
消息队列 |
异步通信,解耦生产者与消费者 |
高并发场景、任务调度 |
- TCP Socket
-
- 面向连接,使用
Socket
(客户端)和ServerSocket
(服务器)。
- 面向连接,使用
-
- 流程:服务器监听端口 → 客户端连接 → 双向数据流(
InputStream
/OutputStream
)。
- 流程:服务器监听端口 → 客户端连接 → 双向数据流(
-
- 示例:java
- UDP Socket
-
- 无连接,使用
DatagramSocket
和DatagramPacket
。
- 无连接,使用
-
- 流程:直接发送 / 接收数据包(需指定目标地址和端口)。
-
- 适用于实时性要求高的场景(如游戏、音视频)。
- 关键注意点
-
- 阻塞 IO 需配合多线程处理并发。
-
- 需处理网络异常(如超时、断开)。
-
- 大数据传输需优化缓冲区。
Socket 是实现 HTTP、数据库连接等上层协议的基础,广泛用于网络通信、分布式系统和微服务架构。
// 服务器:serverSocket.accept() → 获取客户端Socket → 读写数据
// 客户端:new Socket(host, port) → 读写数据
47.TCP
Java TCP 基于 Socket
和 ServerSocket
实现可靠通信:
- 核心机制
-
- 三次握手建立连接,四次挥手关闭连接。
-
- 基于字节流(
InputStream
/OutputStream
),需自定义协议分隔消息边界(如换行符、长度前缀)。
- 基于字节流(
- 并发处理
-
- 单线程模型:一次处理一个客户端,其他客户端阻塞。
-
- 多线程模型:为每个客户端创建独立线程(需注意资源耗尽风险)。
-
- NIO 模型:基于
Selector
实现多路复用,单线程处理多个连接(Java 1.4+)。
- NIO 模型:基于
- 典型问题
-
- 粘包 / 半包:通过
BufferedReader
按行读取或自定义解码器解决。
- 粘包 / 半包:通过
-
- 性能瓶颈:使用线程池(
Executors.newFixedThreadPool
)或异步 IO(Netty 框架)优化。
- 性能瓶颈:使用线程池(
示例:
java
// 服务器:new ServerSocket(port).accept() → 多线程处理Socket
// 客户端:new Socket(host, port) → 获取流读写
48.UDP
Java UDP 基于 DatagramSocket
和 DatagramPacket
实现无连接通信:
- 核心机制
-
- 无需握手,直接发送数据包(
send()
/receive()
)。
- 无需握手,直接发送数据包(
-
- 数据包包含源 / 目标 IP + 端口,最大 65,507 字节(受限于底层协议)。
- 关键特性
-
- 不可靠:可能丢包、乱序、重复。
-
- 低延迟:无需建立连接,适合实时场景(如游戏、音视频)。
- 编程模型
-
- 服务器:绑定端口 → 循环接收数据包(
receive()
阻塞)。
- 服务器:绑定端口 → 循环接收数据包(
-
- 客户端:指定目标地址发送数据包。
-
- 示例:java
// 发送:new DatagramPacket(data, len, address, port)
// 接收:packet.getAddress() 获取发送方地址
- 典型问题
-
- 丢包处理:应用层实现确认机制(如序列号、超时重传)。
-
- 半包问题:UDP 不存在粘包,但需自行处理大数据分片(如手动拆包 / 组包)。
相比 TCP,UDP 更轻量但需应用层补充可靠性逻辑。
49.打印流
打印流(PrintStream
/PrintWriter
)是 Java 简化输出操作的高级流,核心特性:
- 自动刷新:写入换行符或调用
println()
时自动刷新缓冲区。
- 格式化输出:支持
printf()
语法(如%.2f
)。
- 异常处理:方法不抛
IOException
,通过checkError()
检查。
区别:
PrintStream
(字节流):适合二进制数据,默认平台编码。
PrintWriter
(字符流):适合文本,需显式指定编码(如 UTF-8)。
典型场景:
日志输出、数据导出、控制台打印、网络通信。
注意:
- 使用 try-with-resources 确保资源关闭。
- 大数据量时用
BufferedWriter
提升性能。
打印流通过封装底层细节,大幅提升输出效率与代码可读性。
### Java 打印流(PrintStream/PrintWriter)详解
#### 一、打印流是什么?
**打印流** 是 Java 提供的用于简化输出操作的高级流,它封装了底层输出流,并提供了一系列 **print()** 和 **println()** 方法,支持自动换行、格式化输出(如 `printf()`),且无需手动处理 `IOException`。
Java 提供两种打印流:
- **PrintStream**:字节流,处理原始字节数据(如文件、网络)。
- **PrintWriter**:字符流,处理字符数据(如文本),更适合国际化场景。
#### 二、核心特性与优势
##### 1. 自动刷新
打印流可在以下情况自动刷新缓冲区:
- 写入换行符(`\n`)时。
- 调用 `println()` 方法时。
- 构造时指定 `autoFlush = true`(仅对 `println()`、`printf()`、`format()` 有效)。
**示例**:
```java
// 创建自动刷新的 PrintWriter
PrintWriter writer = new PrintWriter(new FileWriter("output.txt"), true);
writer.println("Hello, World!"); // 自动刷新缓冲区
```
##### 2. 格式化输出
支持类似 C 语言 `printf` 的格式化语法:
```java
double pi = Math.PI;
System.out.printf("PI 的值是: %.2f%n", pi); // 输出:PI 的值是: 3.14
```
##### 3. 异常处理简化
打印流的方法不会抛出 `IOException`,而是通过 `checkError()` 方法检查底层错误:
```java
PrintWriter writer = new PrintWriter("file.txt");
writer.println("Data");
if (writer.checkError()) { // 检查并重置错误状态
System.err.println("写入失败");
}
```
#### 三、PrintStream vs PrintWriter
| **特性** | **PrintStream** | **PrintWriter** |
|------------------------|------------------------------|------------------------------|
| **继承关系** | 继承自 `OutputStream`(字节流) | 继承自 `Writer`(字符流) |
| **处理数据类型** | 字节(byte) | 字符(char)和字符串(String) |
| **编码支持** | 需手动指定(如 `new PrintStream(file, "UTF-8")`) | 构造时直接指定编码(如 `new PrintWriter(file, "UTF-8")`) |
| **国际化支持** | 弱(字节流) | 强(字符流,自动处理编码) |
| **应用场景** | 输出二进制数据(如文件、网络) | 输出文本数据(如日志、配置) |
#### 四、常见用法示例
##### 1. 输出到控制台
```java
System.out.println("控制台输出"); // System.out 是 PrintStream
System.err.println("错误输出"); // System.err 也是 PrintStream
```
##### 2. 输出到文件
```java
// 使用 PrintWriter 输出文本文件(自动刷新)
try (PrintWriter writer = new PrintWriter(new FileWriter("output.txt"), true)) {
writer.println("第一行");
writer.printf("格式化输出: %d, %s%n", 123, "abc");
} catch (IOException e) {
e.printStackTrace();
}
// 使用 PrintStream 输出二进制文件
try (PrintStream ps = new PrintStream(new FileOutputStream("data.bin"))) {
ps.write(65); // 写入字节 'A'
ps.println(123); // 写入数字(转为字符串)
} catch (IOException e) {
e.printStackTrace();
}
```
##### 3. 重定向标准输出
```java
// 将 System.out 重定向到文件
PrintStream fileOut = new PrintStream("log.txt");
System.setOut(fileOut);
System.out.println("此内容会被写入 log.txt"); // 不再显示在控制台
```
#### 五、注意事项
1. **资源管理**
打印流包装其他流时,关闭打印流会自动关闭底层流:
```java
// 错误示例:可能导致资源泄漏
OutputStream fos = new FileOutputStream("file.txt");
PrintStream ps = new PrintStream(fos);
ps.close(); // 关闭 ps 会关闭 fos,但未处理异常
// 正确示例:使用 try-with-resources
try (PrintStream ps = new PrintStream(new FileOutputStream("file.txt"))) {
ps.println("Data");
} // 自动关闭 ps 和底层流
```
2. **编码问题**
- `PrintStream` 默认使用平台编码,可能导致乱码。
- 推荐使用 `PrintWriter` 并显式指定编码:
```java
PrintWriter writer = new PrintWriter(
new OutputStreamWriter(new FileOutputStream("file.txt"), StandardCharsets.UTF_8),
true // 自动刷新
);
```
3. **性能考量**
频繁调用 `println()` 可能影响性能,大数据量输出时建议:
- 使用 `BufferedWriter` 包装 `PrintWriter`。
- 批量写入后手动调用 `flush()`。
#### 六、应用场景
- **日志输出**:将程序运行信息写入日志文件。
- **数据导出**:生成 CSV、配置文件等文本格式。
- **调试信息**:在控制台打印调试数据。
- **网络编程**:通过 `Socket` 发送格式化数据。
#### 七、总结
打印流(`PrintStream`/`PrintWriter`)是 Java 中用于简化输出操作的核心工具,通过自动刷新、格式化输出和异常处理封装,显著提升了开发效率。选择 `PrintWriter` 而非 `PrintStream` 可更好地处理国际化和字符编码问题。
50.网络编程基础
- 计算机网络:由两台或更多计算机组成的网络;
- 互联网:连接网络的网络;
- IP地址:计算机的网络接口(通常是网卡)在网络中的唯一标识;
- 网关:负责连接多个网络,并在多个网络之间转发数据的计算机,通常是路由器或交换机;
- 网络协议:互联网使用TCP/IP协议,它泛指互联网协议簇;
- OSI: 七层模型
- IP协议:一种分组交换传输协议;
- TCP协议:一种面向连接,可靠传输的协议;
- UDP协议:一种无连接,不可靠传输的协议。
51.common io
特性 |
Commons IO |
Java NIO |
API 风格 |
简单易用,面向流操作 |
复杂,面向缓冲区和通道 |
适用场景 |
简单文件操作、快速开发 |
高性能网络编程、大数据处理 |
性能 |
适用于中小数据量 |
适用于高并发、大文件 |
阻塞模式 |
基于 BIO(阻塞) |
支持 NIO(非阻塞) |
### Apache Commons IO 简要讲解
**Apache Commons IO** 是简化 Java IO 操作的工具库,提供以下核心功能:
1. **文件操作**
```java
FileUtils.readFileToString(file, "UTF-8"); // 读取文件为字符串
FileUtils.copyDirectory(srcDir, destDir); // 复制目录
FileUtils.deleteQuietly(file); // 安全删除文件
```
2. **流操作**
```java
IOUtils.copy(inputStream, outputStream); // 复制流
IOUtils.closeQuietly(stream); // 安全关闭流
```
3. **路径处理**
```java
FilenameUtils.getExtension("file.txt"); // 获取扩展名
FilenameUtils.normalize("path/../to"); // 规范化路径
```
4. **文件监听**
监控文件变化(创建、修改、删除)。
**优势**:减少样板代码,自动处理异常和资源关闭,跨平台兼容。
**适用场景**:日常文件操作、数据导入导出、临时文件管理。
**依赖**:
```xml
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>2.15.0</version>
</dependency>
```
Apache Commons IO 是简化 Java IO 操作的工具库,提供:
- 文件工具:读写、复制、删除文件 / 目录。
- 流工具:复制流、安全关闭、转换为字符串。
- 路径处理:规范化路径、获取扩展名。
- 文件监听:监控文件变化。
优势:减少样板代码,自动处理异常,跨平台兼容。
典型场景:文件导入导出、日志解析、临时文件管理。
依赖单模块,快速提升开发效率。
52.Java爬虫
维度 |
Java 爬虫 |
Python 爬虫 |
开发效率 |
较低(需编写较多样板代码) |
极高(语法简洁,库丰富) |
学习曲线 |
陡峭(需掌握 OOP、多线程等) |
平缓(入门简单,适合快速原型) |
性能 |
高(编译型语言,适合大规模数据) |
低(解释型语言,IO 密集型更优) |
并发模型 |
多线程(需手动管理线程池) |
协程(asyncio、gevent) |
社区生态 |
丰富(Jsoup、HttpClient、WebMagic) |
超级丰富(Requests、Scrapy、Selenium) |
适用场景 |
大规模分布式爬虫、企业级系统 |
小规模数据采集、快速验证 |
了解即可 学习成本太高 现阶段用python爬虫足够了 pyspider scrapy
53.正则表达式
正则表达式是用于文本匹配的模式工具,通过元字符组合定义规则:
- 基础元字符:
.
(任意字符)、\d
(数字)、^
(开头)、$
(结尾)。
- 限定符:
*
(0 + 次)、+
(1 + 次)、?
(0/1 次)。
- 字符类:
[abc]
(匹配其中之一)、[^0-9]
(非数字)。
- 分组与引用:
()
分组,\1
引用首个分组。
应用场景:数据验证(邮箱、手机号)、文本提取 / 替换。需注意贪婪匹配与性能优化,可通过在线工具(如 Regex101)辅助调试。
### 正则表达式(Regular Expression)详解
#### 一、什么是正则表达式?
正则表达式是一种用于 **匹配、查找和替换文本** 的强大工具,通过定义特定模式(Pattern)来操作字符串。它广泛应用于文本处理、数据验证、爬虫、编辑器搜索替换等场景。
#### 二、核心元字符与语法
##### 1. 基础元字符
| 元字符 | 描述 | 示例 | 匹配结果 |
|--------|--------------------------|--------------------|-------------------|
| `.` | 匹配任意单个字符(除换行符) | `a.c` | `abc`, `a1c` |
| `\d` | 匹配数字(等价于 `[0-9]`) | `\d\d` | `12`, `99` |
| `\w` | 匹配单词字符(字母、数字、下划线) | `\w\w` | `ab`, `a1`, `_1` |
| `\s` | 匹配空白字符(空格、制表符、换行符) | `a\sb` | `a b` |
| `^` | 匹配字符串开头 | `^Hello` | `Hello world` |
| `$` | 匹配字符串结尾 | `world$` | `Hello world` |
##### 2. 限定符(Quantifiers)
| 限定符 | 描述 | 示例 | 匹配结果 |
|--------|--------------------------|--------------------|-------------------|
| `*` | 匹配前面的元素 0 次或多次 | `a*b` | `b`, `ab`, `aab` |
| `+` | 匹配前面的元素 1 次或多次 | `a+b` | `ab`, `aab` |
| `?` | 匹配前面的元素 0 次或 1 次 | `colou?r` | `color`, `colour` |
| `{n}` | 匹配前面的元素恰好 n 次 | `a{3}` | `aaa` |
| `{n,}` | 匹配前面的元素至少 n 次 | `a{2,}` | `aa`, `aaa` |
| `{n,m}`| 匹配前面的元素 n 到 m 次 | `a{2,3}` | `aa`, `aaa` |
##### 3. 字符类(Character Classes)
| 语法 | 描述 | 示例 |
|----------|--------------------------|--------------------|
| `[abc]` | 匹配 a、b 或 c 中的任意一个字符 | `[aeiou]` |
| `[^abc]` | 匹配除 a、b、c 之外的任意字符 | `[^0-9]` |
| `[a-z]` | 匹配指定范围内的任意字符 | `[A-Z0-9]` |
| `[a-zA-Z]` | 匹配字母(大小写) | |
##### 4. 分组与捕获
| 语法 | 描述 | 示例 |
|----------|--------------------------|--------------------|
| `(...)` | 分组,将多个元素视为一个整体 | `(ab)+` |
| `\1` | 反向引用第一个分组 | `(\d)\1` | 匹配 `11`, `22` |
| `(?<name>...)` | 命名分组 | `(?<year>\d{4})` |
##### 5. 特殊字符
| 字符 | 描述 |
|------|--------------------------|
| `\` | 转义字符(如 `\.` 匹配点号) |
| `|` | 或操作(如 `cat|dog`) |
| `()` | 分组(用于限定范围或捕获) |
#### 三、在不同语言中的应用
##### 1. Python
```python
import re
# 匹配邮箱
text = "Contact me at test@example.com"
pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
matches = re.findall(pattern, text)
print(matches) # 输出: ['test@example.com']
# 替换
new_text = re.sub(r'\d+', 'NUMBER', "I have 123 apples")
print(new_text) # 输出: "I have NUMBER apples"
```
##### 2. Java
```java
import java.util.regex.*;
public class RegexExample {
public static void main(String[] args) {
String text = "Hello 123 World";
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher(text);
if (matcher.find()) {
System.out.println(matcher.group()); // 输出: 123
}
}
}
```
##### 3. JavaScript
```javascript
const text = "Hello World";
const pattern = /World/;
console.log(pattern.test(text)); // 输出: true
console.log(text.replace(pattern, "JavaScript")); // 输出: "Hello JavaScript"
```
#### 四、进阶技巧
##### 1. 贪婪匹配 vs 非贪婪匹配
- **贪婪匹配**(默认):尽可能多地匹配。
示例:`a.*c` 匹配 `abcdefc` 时会匹配整个字符串。
- **非贪婪匹配**(加 `?`):尽可能少地匹配。
示例:`a.*?c` 匹配 `abcdefc` 时会匹配 `abc`。
##### 2. 零宽断言(Lookaround)
| 语法 | 描述 | 示例 |
|------------|--------------------------|--------------------|
| `(?=...)` | 正向先行断言(后面必须匹配) | `\w+(?=\d)` | 匹配 `a1` 中的 `a` |
| `(?!...)` | 负向先行断言(后面不能匹配) | `\w+(?!\d)` | 匹配 `ab` 中的 `ab` |
| `(?<=...)` | 正向后行断言(前面必须匹配) | `(?<=\$)\d+` | 匹配 `$100` 中的 `100` |
| `(?<!...)` | 负向后行断言(前面不能匹配) | `(?<!\$)\d+` | 匹配 `100` 但不匹配 `$100` 中的 `100` |
#### 五、常见应用场景
##### 1. 数据验证
- **邮箱**:`^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$`
- **手机号**:`^1[3-9]\d{9}$`
- **URL**:`^https?://\S+(\.\S+)+$`
##### 2. 文本提取
- 提取 HTML 标签:`<[^>]+>`
- 提取数字:`\d+`
##### 3. 文本替换
- 替换敏感词:`(?i)fuck|shit` → `***`
#### 六、性能注意事项
- **避免嵌套量词**:如 `(a+)*` 可能导致指数级回溯。
- **优先使用具体字符类**:如 `[0-9]` 比 `\d` 更明确。
- **编译正则表达式**:在循环中重复使用的正则表达式应预编译(如 Java 的 `Pattern.compile`)。
#### 七、工具推荐
- **在线测试**:[Regex101](https://regex101.com/)、[RegexPal](https://www.regexpal.com/)
- **可视化工具**:[Regexper](https://regexper.com/)
- **IDE 支持**:VS Code、IntelliJ IDEA 等内置正则表达式搜索。
#### 八、总结
正则表达式是处理文本的强大工具,但其语法复杂,需通过练习掌握。核心是理解 **元字符**、**限定符** 和 **分组** 的用法,以及在不同语言中的应用差异。合理使用正则表达式能显著提升文本处理效率,但需注意性能和可读性的平衡。
54.注解
Java 注解是代码元数据,提供配置信息而不直接影响程序逻辑。它通过 @interface
定义,可被编译器、框架或工具解析。内置注解如 @Override
、@Deprecated
等,自定义注解需配合元注解(@Retention
、@Target
)指定作用范围。注解处理分编译时(如Lombok)、运行时(反射获取)和工具处理(如JUnit)。常见于框架配置(Spring)、数据验证(Hibernate)、ORM映射(JPA)。合理使用可提升开发效率,但需避免滥用。
### Java 注解(Annotation)详解
#### 一、注解是什么?
**注解** 是 Java 5 引入的一种元数据机制,用于为代码提供额外的信息(如配置、标记、约束等)。注解本身不直接影响代码逻辑,但可被编译器、框架或工具解析,实现诸如自动配置、代码生成、运行时行为调整等功能。
#### 二、注解的基本语法
1. **内置注解**
Java 提供的标准注解:
```java
@Override // 标记方法重写父类方法
@Deprecated // 标记已过时的方法/类
@SuppressWarnings("unchecked") // 抑制编译器警告
```
2. **自定义注解**
使用 `@interface` 定义,可包含属性:
```java
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME) // 注解保留到运行时
@Target(ElementType.METHOD) // 注解可用于方法
public @interface MyAnnotation {
String value() default ""; // 定义属性,默认值为空字符串
int count() default 1;
}
```
3. **元注解**
用于修饰注解的注解:
- `@Retention`:指定注解的保留策略(SOURCE/CLASS/RUNTIME)。
- `@Target`:指定注解可应用的目标类型(METHOD/TYPE/FIELD等)。
- `@Documented`:使注解在Javadoc中可见。
- `@Inherited`:允许子类继承父类的注解。
#### 三、注解的处理方式
注解的作用取决于其保留策略和处理方式:
1. **编译时处理**
注解被编译器读取,用于生成代码或进行静态检查。
示例:Lombok 通过 `@Data` 注解自动生成 getter/setter 方法。
2. **运行时反射处理**
通过反射机制在运行时获取注解信息,动态调整程序行为。
示例:Spring 通过 `@Autowired` 实现依赖注入:
```java
@Service
public class UserService {
@Autowired // 运行时通过反射注入依赖
private UserRepository repository;
}
```
3. **工具处理**
第三方工具读取注解信息,生成配置文件或报告。
示例:JUnit 的 `@Test` 注解标记测试方法。
#### 四、注解的典型应用场景
1. **框架配置**
Spring 框架通过注解简化配置:
```java
@RestController
@RequestMapping("/api")
public class UserController {
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) { ... }
}
```
2. **单元测试**
JUnit 使用注解标记测试方法:
```java
@Test
public void testAddition() {
assertEquals(4, 2 + 2);
}
```
3. **数据验证**
Hibernate Validator 通过注解实现参数校验:
```java
public class User {
@NotNull(message = "姓名不能为空")
private String name;
@Email(message = "邮箱格式不正确")
private String email;
}
```
4. **ORM映射**
JPA 通过注解定义实体与数据库表的映射:
```java
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
```
#### 五、注解与反射的结合
通过反射获取注解信息是注解最强大的应用方式:
```java
import java.lang.reflect.Method;
public class AnnotationProcessor {
public static void main(String[] args) throws Exception {
Class<?> clazz = MyClass.class;
Method method = clazz.getMethod("myMethod");
// 检查方法是否有特定注解
if (method.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
System.out.println("Value: " + annotation.value());
System.out.println("Count: " + annotation.count());
}
}
}
@MyAnnotation(value = "test", count = 3)
class MyClass {
public void myMethod() {}
}
```
#### 六、自定义注解实战示例
以下是一个自定义注解实现权限校验的示例:
1. **定义注解**
```java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequiresPermission {
String value(); // 权限名称
}
```
2. **注解处理器**
```java
public class SecurityInterceptor {
public static boolean checkPermission(Method method) {
if (method.isAnnotationPresent(RequiresPermission.class)) {
RequiresPermission permission = method.getAnnotation(RequiresPermission.class);
// 模拟权限校验逻辑
return UserContext.getCurrentUser().hasPermission(permission.value());
}
return true;
}
}
```
3. **使用注解**
```java
public class UserController {
@RequiresPermission("admin")
public void deleteUser(Long userId) {
// 删除用户逻辑
}
}
```
#### 七、注意事项
1. **性能开销**
反射读取注解会带来一定性能损耗,避免在高并发场景频繁使用。
2. **注解滥用**
避免过度使用注解导致代码可读性下降,复杂逻辑建议使用配置文件。
3. **兼容性**
自定义注解需考虑版本兼容性,新增属性时注意默认值。
#### 八、总结
Java 注解通过元数据增强代码表达力,结合反射机制可实现强大的动态功能。常见应用包括框架配置(如 Spring)、数据验证、测试框架等。理解注解的定义、处理方式及与反射的结合,是掌握 Java 高级编程的关键之一。
55.反射
### Java 反射机制详解
#### 一、反射是什么?
Java 反射(Reflection)是指在 **运行时** 动态获取类的信息(如属性、方法、构造器)并操作对象的能力。通过反射,程序可以在运行时:
- 检查类、方法、字段的信息。
- 创建对象、调用方法、修改属性。
- 动态加载类(如插件机制)。
#### 二、核心类与 API
##### 1. `Class` 类
`Class` 是反射的核心,每个类都有唯一的 `Class` 对象,获取方式:
```java
// 方式1:通过类名
Class<?> clazz = String.class;
// 方式2:通过对象实例
String str = "hello";
Class<?> clazz = str.getClass();
// 方式3:通过全类名(需处理 ClassNotFoundException)
Class<?> clazz = Class.forName("java.lang.String");
```
##### 2. `Field` 类(字段)
获取和操作类的属性:
```java
Class<?> clazz = Person.class;
Field field = clazz.getDeclaredField("name"); // 获取私有字段
field.setAccessible(true); // 打破访问权限限制
Person person = new Person();
field.set(person, "Alice"); // 设置属性值
String name = (String) field.get(person); // 获取属性值
```
##### 3. `Method` 类(方法)
获取和调用类的方法:
```java
Class<?> clazz = Person.class;
Method method = clazz.getMethod("sayHello", String.class); // 获取方法
Person person = new Person();
String result = (String) method.invoke(person, "World"); // 调用方法
```
##### 4. `Constructor` 类(构造器)
动态创建对象:
```java
Class<?> clazz = Person.class;
Constructor<?> constructor = clazz.getConstructor(String.class, int.class); // 获取构造器
Person person = (Person) constructor.newInstance("Bob", 25); // 创建对象
```
#### 三、反射的应用场景
##### 1. 框架开发
- **Spring**:通过反射实现依赖注入(如 `@Autowired`)。
- **MyBatis**:通过反射映射 SQL 查询结果到对象。
##### 2. 序列化与反序列化
- JSON 库(如 Jackson)通过反射将 JSON 字符串转为对象。
##### 3. 单元测试
- 通过反射访问私有方法或属性进行测试。
##### 4. 动态代理
- Java 的 `Proxy` 类通过反射实现 AOP(如事务管理)。
#### 四、反射的优缺点
##### 1. 优点
- **灵活性高**:运行时动态操作类,适合框架开发。
- **解耦**:减少代码间的硬依赖(如插件机制)。
##### 2. 缺点
- **性能开销大**:反射操作比直接调用慢(约 10-100 倍)。
- **破坏封装性**:可访问私有成员,违反面向对象原则。
- **安全性风险**:可能导致信息泄露或恶意操作。
#### 五、反射的性能优化
1. **缓存反射对象**:避免重复获取 `Class`、`Method` 等对象。
2. **使用 `setAccessible(true)`**:减少访问检查开销。
3. **结合 LambdaMetaFactory**:Java 8+ 可生成动态调用器提升性能。
#### 六、反射与泛型的关系
泛型在编译后会被擦除(Type Erasure),但通过反射仍可获取泛型信息:
```java
public class GenericClass<T> {
private T value;
}
// 通过反射获取泛型类型
Class<?> clazz = GenericClass.class;
Type type = clazz.getGenericSuperclass();
ParameterizedType paramType = (ParameterizedType) type;
Type[] typeArgs = paramType.getActualTypeArguments(); // 获取泛型参数
```
#### 七、反射的安全性限制
- **模块系统限制**(Java 9+):需在 `module-info.java` 中声明 `opens` 模块。
- **安全管理器(SecurityManager)**:可能禁止某些反射操作。
#### 八、示例代码:动态调用方法
```java
import java.lang.reflect.Method;
public class ReflectionExample {
public static void main(String[] args) throws Exception {
// 获取 Class 对象
Class<?> clazz = Class.forName("java.util.ArrayList");
// 创建实例
Object list = clazz.getDeclaredConstructor().newInstance();
// 调用 add 方法
Method addMethod = clazz.getMethod("add", Object.class);
addMethod.invoke(list, "Hello");
addMethod.invoke(list, "World");
// 调用 size 方法
Method sizeMethod = clazz.getMethod("size");
int size = (int) sizeMethod.invoke(list);
System.out.println("Size: " + size); // 输出: Size: 2
}
}
```
#### 九、总结
Java 反射是一把“双刃剑”,它提供了强大的动态编程能力,但也带来了性能和安全风险。合理使用反射可以构建灵活的框架(如 Spring、Hibernate),但在性能敏感场景(如高频交易系统)应谨慎使用。理解反射机制是深入掌握 Java 高级编程的关键之一。
总结
### 核心技术快速回顾
1. **Hutool工具库**
- 轻量级Java工具类库,封装字符串、集合、IO、加密等常用功能。
- 模块丰富(如hutool-core、hutool-http),支持简化开发流程,提升效率。
2. **Socket与网络编程**
- **TCP**:面向连接,可靠传输,用ServerSocket/Socket实现,需处理粘包、多线程并发。
- **UDP**:无连接,不可靠,用DatagramSocket实现,适合实时场景(如游戏)。
- 对比HTTP:Socket是底层接口,需自定义协议;HTTP基于请求-响应,适合Web场景。
3. **打印流(PrintStream/PrintWriter)**
- 简化输出操作,支持自动刷新、格式化输出(printf)。
- PrintStream处理字节流,PrintWriter处理字符流,需注意编码和资源关闭。
4. **网络编程基础**
- 核心概念:IP地址、网关、TCP/IP协议、OSI七层模型。
- 协议对比:TCP可靠但延迟高,UDP反之;HTTP基于TCP,无状态。
5. **Apache Commons IO**
- 简化IO操作,提供文件读写、流复制、路径处理等工具类。
- 对比Java NIO:易用性高,适合中小数据量;NIO适合高性能、大文件场景。
6. **Java爬虫**
- 与Python对比:Java适合大规模分布式爬虫,开发效率低;Python库丰富,适合快速验证。
- 现阶段建议优先学习Python爬虫(如Scrapy)。
7. **正则表达式**
- 元字符(如.、\d)、限定符(*、+)、分组(())构建匹配模式。
- 应用:数据验证(邮箱、手机号)、文本提取,需注意贪婪匹配与性能优化。
8. **注解与反射**
- **注解**:元数据机制,分内置(@Override)、自定义(配合元注解),用于框架配置、数据验证。
- **反射**:运行时动态操作类,性能开销大,用于Spring依赖注入、序列化,需谨慎使用。