Java record 是 Java 14 预览、15 正式发布的不可变数据载体,以一行语法替代十几行手工代码,JVM 为其生成优化字节码,内存更紧凑、运行时行为更安全,但仅适用于纯数据场景。

Java record 是 Java 14 引入(Java 14 预览,Java 15 正式发布)的不可变数据载体类型,它在语义、内存布局和代码编写上与普通类有本质区别。对比核心在于:record 用极简语法表达“仅用于封装数据”的意图,JVM 会为其生成高度优化的字节码,而普通类需手动编写构造器、访问器、equals/hashCode/toString 等,不仅代码量多,还容易出错且可能引入不必要的对象开销。
代码量差异:一行 vs 十几行
定义一个包含 name(String)和 age(int)的简单数据结构:
- record 写法(1 行):
record Person(String name, int age) {} - 等效的普通类(典型实现约 15–20 行):需显式声明字段、全参构造器、getter 方法(无 setter)、重写 equals、hashCode、toString,还要考虑 null 安全(如 Objects.equals)、字段 final 修饰等。
更关键的是,record 自动生成的方法是经过 JVM 特别优化的:例如 toString() 不通过反射拼接,而是编译期生成硬编码字符串;equals/hashCode 使用字段值直接计算,避免运行时反射或泛型擦除带来的间接调用开销。
内存占用:更紧凑,无冗余字段
record 编译后仍是一个普通 class(继承自 java.lang.Record),但其字段全部为 final 且私有,JVM 可对其做更多激进优化:
立即学习“Java免费学习笔记(深入)”;
- 字段无法被子类覆盖或动态修改,JIT 编译器更容易内联访问、消除冗余读取;
- 没有额外的实例字段(比如普通类中常出现的 transient 标志位、缓存字段、状态标记等);
- record 的组件字段(components)在字节码中以连续顺序布局,与普通类相比,对象头 + 字段对齐后的总大小通常更小(尤其在大量小对象场景下,如 DTO 列表)。
实测:在 OpenJDK 17+ 上,Person record 实例的 shallow size(不计 String 引用本身)通常比等效普通类少 4–8 字节——主要省在避免了隐式生成的 synthetic 字段和更优的字段对齐策略。
运行时行为差异:不可变性与语义保证
record 的不可变性不是靠约定,而是由语言强制:
- 所有字段隐式 final,且无默认无参构造器,无法绕过初始化;
- 自动实现的 equals/hashCode/toString 基于组件值(而非引用),且严格按声明顺序;
- 不能继承其他类(只能实现接口),避免破坏值语义;
- JVM 知道这是 record,可在序列化(如 JEP 395 支持)、模式匹配(switch + record)等场景提供原生支持,减少中间对象创建。
而普通类若想达到相同效果,需人工保障:比如忘记加 final、误写可变 setter、equals 中漏判某个字段、toString 打印了内部状态而非业务字段……这些都会导致内存中存在逻辑重复或行为不一致的对象。
适用边界:不是万能替代品
record 适合“纯数据”场景,不适用于:
- 需要封装行为(复杂方法逻辑、状态变更、资源管理);
- 需深度继承体系(record 不能被继承,也不能继承非 Record 类);
- 字段需延迟加载、缓存计算、或依赖外部上下文(record 构造器必须完成全部字段初始化);
- 需兼容老版本 JDK(
此时普通类仍是必要选择,但可通过 Lombok @Value 或 IDE 模板减少样板代码——只是无法获得 record 的 JVM 层语义支持与内存优化。










