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

JEP-395

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

  • 对于header中的每个组件,有两个成员:一个public accessor method,同名,返回类型与组件相同,private final field,与组件同名;

~如果生成的 final 字段与访问方法同名,为什么不生成 public final 字段呢?~


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

所以改变 API 内部实现(记录组件)不是一个合适的理由。但我有充分的理由来自 @Brian Goetz

谢谢大家关注我的傻问题

stack overflow Why do Java Records have accessor methods instead of public final fields?
原文答案

答案:

作者头像

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

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

在评论中引用 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 在对 this answer 的评论中提供了另一个原因:

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

作者头像

我认为这个决定的一个关键因素是你现在有能力 override 记录的吸气剂:

public record MyRecord(String myProperty) {
    @Override
    public String myProperty() {
        return "The property is " + myProperty;
    }
}

对于公共最终字段,这样的事情是不可能的。

作者头像

通常最好的做法是使用访问器方法而不是直接字段访问。即使有记录,继续这种做法也很有意义,例如,在不破坏现有代码的情况下重命名字段。

作者头像

Java 程序员绝对是不必要的封装者 addicted 。他们看着公开的决赛场地,在迷信的反感中退缩。所以我们让人们做出疯狂的下意识的陈述,比如“直接访问你的字段没有意义(编程封装的基本原理)”,以及一些古怪的推理,即强制命名约定是合理的(get/set 和 bizarrely 是)作为 only 处理数据的正确方法 - 尽管您不知道这些方法实现 actually 做了什么。

当然,之所以坚持它,是因为该语言的 baffling 决定在过去 30 年的任何时候都不将属性实现为该语言的内置特性(如 C#、Kotlin)。相反,他们花了十年时间反复尝试对语言进行模块化,但最终失败了(自从它最终出现以来,这是一个几乎没有使用过的功能)。

Records 的引入将是一劳永逸地正确实现属性的绝佳机会(毕竟,这是一个非常简单的增强 - 在编译器的 desugar pass 中实现它,这是一天的工作,我自己完成了;再过几天为所有可访问的字段添加属性侦听器支持)。但还是不行。

所以,吐槽一下,回到问题。公共最终字段将是一个更明智的实现,使用 option 将字段设为私有( record R (private int foo, int bar) ),其中绝对需要封装。更好的是,不可变装饰器中集合/映射的自动包装可以很容易地实现(声明 List 和自动生成的构造函数确保字段接收不可变 List ),删除自动封装的唯一引人注目的参数一个不可变的 POJO 字段。

但这会违背对 Java 社区中普遍存在的公共 final 字段的(错误的)偏见。