record是为不可变数据建模的语法糖,适用于http响应体、数据库查询结果等纯数据载体场景;字段默认final不可变,不支持继承、setter或private字段,需手动防御性拷贝可变成员。

Record 就是为不可变数据建模的语法糖,不是万能 DTO 工具,用错场景反而更麻烦。
什么时候该用 record 而不是 class
只在你明确需要「纯数据载体 + 不可变性 + 自动生成基础方法」时才用。比如 HTTP 响应体、数据库查询结果映射、函数间简单传参。
- 要字段可变?别用 ——
record的字段默认final,强行加 setter 会破坏语义 - 要继承或实现复杂逻辑?别用 ——
record不能 extends 其他类,且隐式 final,无法被继承 - 要自定义序列化行为(比如忽略某个字段)?小心 ——
record的toString()/equals()是按字段全量生成的,改起来比普通类更绕 - 字段类型含可变对象(如
ArrayList)?记得手动防御性拷贝 ——record不会帮你深拷贝
record 构造器和字段访问的隐含规则
声明 record 时写的参数列表,既是构造器参数,也是公共 final 字段,还决定 equals() 和 hashCode() 的计算范围。
- 所有字段自动是
public final,不支持private字段声明 - 不能定义与组件名同名的普通字段(会编译错误),但可以定义静态字段
- 可以写紧凑构造器(compact constructor),用于校验或规范化输入:
record User(String name, int age) { public User { if (name == null || name.isBlank()) throw new IllegalArgumentException("name required"); if (age < 0) age = 0; // 自动赋值给 this.age } } - 不要在紧凑构造器里调
this.xxx = yyy—— 编译报错;赋值直接写变量名即可
JSON 序列化时常见的坑(Jackson / Gson)
大多数 JSON 库对 record 支持良好,但默认行为可能和你预期不一致。
立即学习“Java免费学习笔记(深入)”;
- Jackson 2.12+ 默认能识别
record,但若字段是private或用了非标准命名,需显式加@JsonCreator和@JsonProperty - Gson 2.10+ 支持 record,但默认不开启无参构造器 fallback —— 如果 record 没有零参构造器(它本来就没有),且没配
GsonBuilder.registerTypeAdapter(),反序列化会失败 - 字段名含下划线或驼峰不匹配?别依赖默认映射 —— 显式用
@JsonProperty("user_name")标注参数名,而不是字段名(record 没字段声明位置) - 泛型 record(如
record Result<t>(T data)</t>)在反序列化时需传TypeToken,否则T会被擦除成Object
record 的简洁性建立在约束之上:它省掉的是模板代码,不是设计权衡。一旦你需要控制字段可见性、生命周期、序列化细节或运行时行为,就该退回到普通 class —— 不是倒退,是回归合理抽象层级。










