Java record是Java 14引入的预览特性,在Java 16正式转正,它主要用来创建不可变的数据载体类,减少传统POJO类中大量重复的样板代码。很多开发者在使用时会发现record定义的类不需要手动写getter、构造器,也不需要实现equals、hashCode、toString方法,同时它的实例创建后字段无法被修改,这背后和final字段的自动添加规则密切相关。
Java record的基本定义形式
定义一个record非常简单,只需要使用record关键字,在声明时指定组件的参数即可,这些参数会自动成为record的字段。下面是一个基础的用户信息record示例:
// 定义一个表示用户信息的record
public record UserRecord(String name, int age, String email) {
}
这个record定义了三个组件:name、age、email,我们不需要手动编写任何构造器、getter方法或者字段声明,编译器会自动帮我们生成这些内容。
final字段的自动添加规则
Java编译器在处理record定义时,会遵循明确的final字段添加规则:
- 所有在record声明中定义的组件参数,都会被自动转换为
private final修饰的实例字段 - record类本身会被自动标记为
final,因此record不能被继承 - record不会生成任何可以修改字段内容的setter方法,从根源上避免字段被修改
我们可以通过反编译上面的UserRecord来查看编译器生成的实际代码,反编译后的核心内容如下:
// 反编译后的UserRecord类结构,省略了方法细节
public final class UserRecord extends java.lang.Record {
// 自动添加的private final字段
private final String name;
private final int age;
private final String email;
// 自动生成的包含全部参数的构造器
public UserRecord(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
// 自动生成的getter方法,方法名和组件名一致,不是getXxx形式
public String name() { return this.name; }
public int age() { return this.age; }
public String email() { return this.email; }
// 自动生成的equals、hashCode、toString方法省略
}
从反编译结果可以明确看到,所有组件对应的字段都被自动添加了private final修饰,同时record类本身是final的,没有生成任何修改字段的方法,这就从结构上保障了record的不可变性。
record不可变性的实现原理
record的不可变性是通过多个层面共同保障的,final字段的自动添加只是其中一部分:
字段层面的限制
如前面提到的,所有record的实例字段都是final的,一旦在构造器中初始化完成,就无法再被修改,这是不可变性的基础。
类层面的限制
record类被自动标记为final,无法被其他类继承,避免了子类重写方法破坏不可变性的可能。
方法层面的限制
编译器不会为record生成任何setter方法,所有的getter方法都只是返回字段的值,不会修改字段内容。同时如果字段是可变对象的引用,需要注意record只是保证引用不可变,对象本身的内容还是可以被修改的,这一点和普通final引用字段的特性一致。
下面的示例展示了可变对象引用的情况:
import java.util.Date;
public record TaskRecord(String taskName, Date createTime) {
}
public class Test {
public static void main(String[] args) {
Date now = new Date();
TaskRecord task = new TaskRecord("测试任务", now);
// 可以修改Date对象本身的内容,因为record只保证createTime引用不变,不保证对象内容不变
now.setTime(0);
System.out.println(task.createTime().getTime()); // 输出0,说明对象内容被修改了
}
}
和传统Java类的对比
如果我们手动写一个和record功能类似的不可变类,需要手动添加很多代码,和record的自动生成形成鲜明对比:
| 特性 | 传统不可变类 | Java record |
|---|---|---|
| 类修饰 | 需要手动加final | 自动添加final |
| 字段修饰 | 需要手动加private final | 自动添加private final |
| 构造器 | 需要手动编写包含所有字段的构造器 | 自动生成包含所有组件的构造器 |
| getter方法 | 需要手动编写,通常是getXxx形式 | 自动生成,方法和组件名同名 |
| equals/hashCode/toString | 需要手动重写或者依赖Lombok等工具 | 自动基于所有组件生成 |
注意事项
在使用record的时候,需要注意以下几点:
- record不能显式声明实例字段,除了静态字段之外,所有的实例状态都必须通过组件参数定义
- record不能声明为抽象类,也不能被继承
- 如果record的组件包含可变对象的引用,要注意对象本身的可变性,避免意外修改内容
- record适合用来做简单的数据载体,不适合包含复杂的业务逻辑,因为它的设计目标就是轻量级的数据类
总的来说,Java record通过自动为所有组件添加private final字段、将类标记为final、不生成修改字段的方法,全方位保障了其不可变性,开发者不需要手动编写大量样板代码就可以得到不可变的数据类,大大提升了开发效率。
Java_record不可变性final字段自动添加规则修改时间:2026-06-18 18:33:48