为什么JavaRecords有访问器方法而不是公共final字段?

JEP-395说

一个记录类自动获取许多标准成员:

  • 对于头部中的每个组件,两个成员:一个组件同名且返回类型相同公共访问器方法,以及一个与组件类型相同的私有 final 字段

如果生成的 final 字段与访问器方法具有相同的名称,为什么不生成公共 final 字段呢?


由于记录类的实例可以序列化和反序列化,因此记录组件几乎不会被小心地更改。但是,不能通过提供 writeObject、readObject、readObjectNoData、writeExternal 或 readExternal 方法来自定义流程

所以改变 API 内部实现(记录组件)不是一个合适的理由。但我从@Brian Goetz那里得到了充分的理由

谢谢大家关注我的傻问题

回答

记录可以实现接口,因此记录的访问器可以是接口方法的实现。此外,使用访问器而不是直接字段访问提供了更大的灵活性,例如,您可以将直接返回字段的访问器替换为以某种方式派生值的访问器(反之亦然)。

记录还允许您覆盖访问器 - 而不是简单地返回字段 - 做一些额外的事情。使记录使用直接字段访问会限制和限制您可以对记录执行的操作,从而限制它们的有用性,而让访问器为您提供直接字段访问提供的基线,并在必要时能够执行更多操作。

引用Holger在评论中提供的示例:

public record R(int a, int b) { public int c() { return …; }}public record R(int a, int c) { public int b() { return …; }}提供相同的 API,无论它们的内部表示如何。

简而言之,为字段生成访问器比直接字段访问提供了更多的灵活性和功能。这同样适用于普通的不可变类。

Brian Goetz在对此答案的评论中提供了另一个原因:

如果没有覆盖访问器的能力,记录将无法正确支持可变对象(例如数组)作为组件。如果您有一个数组组件,您可能希望在构造函数和访问器中执行防御性复制(这也需要覆盖 equals,以保留 Record 的规范);如果它是公共 final 字段,则无法封装组件的可变性

  • @DonggiKim Why would it? The fact accessors are methods simply offers you more flexibility than the straight-jacket of direct fields access. You don't have to use the fact you can explicitly implement the accessor (and in most cases you probably shouldn't use it), but if you need to, you can. You can also use it for evolution of a record, for example, add a field that was previously calculated, or split something that used to be a single field into multiple fields, but then add a method to replace the accessor, ensuring binary compatibility, etc.
  • @DonggiKim the motivation for encapsulation is the same as for other, non-record classes. E.g., the classes `public record R(int a, int b) { public int c() { return …; }}` and `public record R(int a, int c) { public int b() { return …; }}` provide the same API, regardless of their internal representation.

以上是为什么JavaRecords有访问器方法而不是公共final字段?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>