java 16的record必须显式声明所有字段于圆括号内,不可增删或设setter;支持泛型但需保障值语义,字段引用不可变而内容需手动防护;不支持继承,仅可实现接口;json序列化需jackson 2.14+或gson显式适配。

Record类在Java16中必须显式声明所有字段,不能省略构造参数
Java 16 的 record 不是语法糖式的“自动补全”,它强制你把所有逻辑上构成值语义的字段都列在声明括号里。漏掉一个字段,就无法通过编译;多写一个没用的字段,反而污染不可变契约。
常见错误是试图像普通类那样后期添加字段或提供 setter:record User(String name) { String email; } —— 这会直接报错,因为 email 没出现在头括号中,也不属于隐式生成的组件。
- 所有字段必须出现在
record声明的圆括号内,例如:record Point(int x, int y) {} - 字段名即为访问器方法名(
x()、y()),不加get前缀 - 不能定义与自动生成的
public final字段同名的显式字段 - 若需额外校验(如非空),必须重写规范构造器:
record User(String name) { public User { if (name == null) throw new IllegalArgumentException(); } }
Record默认不支持JSON序列化,需适配Jackson或Gson
虽然 record 自动生成了 equals、hashCode 和 toString,但主流 JSON 库默认不认识它的构造方式,直接 ObjectMapper.writeValueAsString(new Person("Alice")) 很可能抛出 InvalidDefinitionException。
这是因为 Jackson 默认尝试调用无参构造器,而 record 只有全参构造器;Gson 同样默认跳过 record 组件字段。
- Jackson 2.12+ 支持 record,但需启用模块:
new ObjectMapper().registerModule(new SimpleModule().addDeserializer(...)),更稳妥的是升级到 2.14+ 并确保启用DefaultIndenter和JsonInclude.Include.NON_NULL等兼容配置 - Gson 需显式注册
TypeAdapter,或使用GsonBuilder.registerTypeAdapter(Person.class, new RecordTypeAdapter()) - 避免依赖
@AllArgsConstructor或 Lombok 注解——record 和 Lombok 在同一类中混用会导致编译失败
Record不能继承其他类,也不能被继承,但可实现接口
这是设计使然:record 的本质是“值类”(value class),JVM 要求其具备确定的内存布局和不可变性保障。因此 extends 和 final 语义已被硬编码进字节码,连 javap -c 都能看到编译器插入的 final 修饰符。
你可能会想“让 User 继承 BaseEntity”,但这么做会立刻触发编译错误:error: records are not allowed to extend classes。
- record 只能
implements接口,比如record User(...) implements Serializable, Comparable<user></user> - 若需共享行为,应提取为接口 default 方法,而非父类继承
- 不要试图用反射绕过限制——
setAccessible(true)对 record 字段无效,其字段始终是final且 JVM 层面禁止修改 - 泛型 record 是合法的,如
record Result<t>(T value, boolean success)</t>,但类型擦除后仍受上述规则约束
Record字段类型含可变对象时,只读性需手动防护
record 保证的是字段引用不可变(final),不是字段指向的对象内容不可变。如果字段类型是 ArrayList、HashMap 或自定义可变类,外部仍可通过 getter 获取引用并修改内部状态,破坏值语义。
典型误用:record Config(List<string> hosts) {}</string>,调用方拿到 config.hosts().add("evil.com") 就悄悄污染了本该只读的数据载体。
- 优先使用不可变集合:用
List.of()、Set.copyOf()、Map.ofEntries()构造参数,或在构造器中封装:record Config(List<string> hosts) { public Config { this.hosts = List.copyOf(hosts); } }</string> - 对自定义类型,确保其本身也是 record、
final类,或至少提供不可变视图(如Collections.unmodifiableList) - 避免在 record 中暴露原始数组字段(
int[] data),改用List<integer></integer>或封装为不可变容器
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











