java
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* 图片收集计划
*/
@Data
public class ImageCollectionPlan implements Serializable {
/**
* 内容图片搜索任务列表
*/
private List<ImageSearchTask> contentImageTasks;
/**
* 插画图片搜索任务列表
*/
private List<IllustrationTask> illustrationTasks;
/**
* 架构图生成任务列表
*/
private List<DiagramTask> diagramTasks;
/**
* Logo生成任务列表
*/
private List<LogoTask> logoTasks;
/**
* 内容图片搜索任务
* 对应 ImageSearchTool.searchContentImages(String query)
*/
public record ImageSearchTask(String query) implements Serializable {}
/**
* 插画图片搜索任务
* 对应 UndrawIllustrationTool.searchIllustrations(String query)
*/
public record IllustrationTask(String query) implements Serializable {}
/**
* 架构图生成任务
* 对应 MermaidDiagramTool.generateMermaidDiagram(String mermaidCode, String description)
*/
public record DiagramTask(String mermaidCode, String description) implements Serializable {}
/**
* Logo生成任务
* 对应 LogoGeneratorTool.generateLogos(String description)
*/
public record LogoTask(String description) implements Serializable {}
}
如何理解record
一、record 是什么?
record 是 Java 16 引入的一种特殊的类 ,专门用于创建不可变的数据载体(也叫 "数据类")。它的核心目的是简化只用来存储数据、不需要复杂业务逻辑的类的编写。
简单来说:你定义一个 record,Java 会自动帮你生成:
- 所有字段的私有 final 成员变量
- 全参构造方法
- 每个字段的 getter 方法(注意:getter 名不是
getXxx(),而是直接用字段名,比如query()而不是getQuery()) - 重写的
equals()、hashCode()(基于所有字段) - 重写的
toString()(包含所有字段名和值)
二、结合代码理解 record 的用法
在你的代码中,ImageSearchTask、IllustrationTask 等都是用 record 定义的,我们以 ImageSearchTask 为例拆解:
java
运行
java
// 定义一个 record,括号里是它的核心字段
public record ImageSearchTask(String query) implements Serializable {}
这一行代码,等价于手动编写下面这段冗长的代码:
java
运行
java
public final class ImageSearchTask implements Serializable {
// 私有、不可变的成员变量
private final String query;
// 全参构造方法
public ImageSearchTask(String query) {
this.query = query;
}
// getter 方法(无 get 前缀)
public String query() {
return this.query;
}
// 自动生成的 equals 和 hashCode
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ImageSearchTask that = (ImageSearchTask) o;
return Objects.equals(query, that.query);
}
@Override
public int hashCode() {
return Objects.hash(query);
}
// 自动生成的 toString
@Override
public String toString() {
return "ImageSearchTask[query=" + query + "]";
}
}
再看更复杂的 DiagramTask:
java
运行
java
public record DiagramTask(String mermaidCode, String description) implements Serializable {}
它会自动生成包含 mermaidCode 和 description 两个字段的构造方法、mermaidCode()/description() getter、以及基于这两个字段的 equals/hashCode/toString。
java
import java.io.Serializable;
import java.util.Objects;
// record 隐式为 final 类,且默认继承 java.lang.Record(不能手动改)
public final class DiagramTask implements Serializable {
// 1. 自动生成:所有字段为 private final(不可变)
private final String mermaidCode;
private final String description;
// 2. 自动生成:全参构造方法(参数顺序与 record 定义的字段顺序完全一致)
public DiagramTask(String mermaidCode, String description) {
// 严格按参数顺序赋值,无默认值,必须传全参
this.mermaidCode = mermaidCode;
this.description = description;
}
// 3. 自动生成:getter 方法(无 get 前缀,直接用字段名作为方法名)
public String mermaidCode() {
return this.mermaidCode;
}
public String description() {
return this.description;
}
// 4. 自动生成:equals() 方法(基于所有字段的值比较)
@Override
public boolean equals(Object o) {
// 第一步:引用地址相同,直接返回 true
if (this == o) return true;
// 第二步:对象为 null 或类型不一致,返回 false(严格匹配类类型,不考虑子类)
if (o == null || getClass() != o.getClass()) return false;
// 第三步:强转后逐个比较字段值
DiagramTask that = (DiagramTask) o;
return Objects.equals(mermaidCode, that.mermaidCode)
&& Objects.equals(description, that.description);
}
// 5. 自动生成:hashCode() 方法(基于所有字段的哈希值计算)
@Override
public int hashCode() {
// 按字段顺序组合哈希值,只要有一个字段不同,哈希值大概率不同
return Objects.hash(mermaidCode, description);
}
// 6. 自动生成:toString() 方法(包含类名 + 所有字段名和值)
@Override
public String toString() {
// 格式固定:类名[字段名1=值1, 字段名2=值2]
return "DiagramTask[" +
"mermaidCode=" + mermaidCode +
", description=" + description +
"]";
}
}
三、record 的核心特点(新手必知)
- 不可变性 :
record的字段默认是final的,创建对象后无法修改(比如创建ImageSearchTask后,不能改它的query值),这符合 "数据载体" 的设计初衷。 - 简洁性:用一行代码替代几十行模板代码,大幅减少冗余。
- 可实现接口 :比如你的代码中所有
record都实现了Serializable,这是允许的。 - 不能继承 / 被继承 :
record隐式是final的,不能作为父类;也不能继承其他类(但可以实现接口)。 - 适合场景:只用来存储数据、无业务逻辑的类(比如 DTO、VO、数据传输对象、任务参数类等),就像你代码中的各种 Task 类(只存查询词、描述等数据)。
四、为什么这段代码要用 record?
ImageCollectionPlan 中的 ImageSearchTask、IllustrationTask 等都是 "任务参数类":
ImageSearchTask只需要存储 "图片搜索的关键词(query)"DiagramTask只需要存储 "mermaid 代码" 和 "描述"- 这些类不需要修改字段、不需要复杂方法,只需要存储数据 + 基础的比较 / 打印功能
用 record 正好契合这个需求,既简洁又符合 Java 最佳实践。
总结
record是 Java 简化 "数据载体类" 编写的语法糖,自动生成构造方法、getter、equals/hashCode/toString。record的字段默认不可变(final),适合存储无需修改的纯数据。- 代码中的各类 Task 用
record定义,是因为它们仅作为 "任务参数容器",无业务逻辑,完美匹配record的使用场景。