JEP-395 says
a record class acquires many standard members automatically:
- For each component in the header, two members: a public accessor method with the same name and return type as the component, and a private final field with the same type as the component;
If a generated final field has got the same name as the accessor method, why isn't a public final field generated instead?
Records can implement interfaces, so the accessor of a record could be an implementation of an interface method. Furthermore using accessors instead of direct field access provides more flexibility, for example you can replace an accessor that directly returns a field with an accessor that derives a value in some way (or vice versa).
Records also allow you to override accessors to - instead of just plainly returning the field - do something extra. Making records use direct field access would restrict and limit what you could do with records, and thus limit their usefulness, while having accessors offers you the baseline offered by direct field access with the ability to do more if necessary.
To quote an example provided by Holger in the comments:
the classes
public record R(int a, int b) { public int c() { return …; }}andpublic record R(int a, int c) { public int b() { return …; }}provide the same API, regardless of their internal representation.
In short, generating accessors for fields offers more flexibility and features than direct field access. The same also applies to plain immutable classes.
Another reason is provided by Brian Goetz in the comments on this answer:
Without the ability to override accessors, records would be unable to properly support mutable objects (such as arrays) as components. If you have an array component, you may want to perform a defensive copy in the constructor and accessor (which would also require overriding equals, in order to preserve the specification of Record); if it was a public final field, you could not encapsulate the mutability of your components
I think a key factor in this decision was that you now have the ability to override the Record's getters:
public record MyRecord(String myProperty) {
@Override
public String myProperty() {
return "The property is " + myProperty;
}
}
Something like this would not be possible with public final fields.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With