Was ist ein Record?v.14

Records sind, ähnlich enum-Typen, spezielle Klassen zur Speicherung unveränderlicher Daten, die den Schreibaufwand für den Entwickler gegenüber einer Klassendeklaration erheblich verringern.

v.14Dient eine Klasse lediglich zum Kapseln unveränderlicher Daten in ihren Variablen, etwa im Rahmen von Datenbankabfragen o.ä., so muss auch für sie üblicherweise eine Menge lästiger Code geschrieben werden: Accessor-Methoden, hashCode(), equals() und toString() müssen erstellt, bzw überschrieben werden. Dies wird durch Records erheblich vereinfacht, da die genannten Methoden bei diesen intern automatisch definiert werden.

Im simpelsten Fall sieht die Deklaration eines Record wie folgt aus:

record Moped(String name, String type, int baujahr, int ps) {}

Nach dem Schlüsselwort record und dem Namen wird lediglich eine kommaseparierte Liste von Argumenten in runden Klammern, gefolgt von einem leeren Block notiert.
Ein Objekt wird dann wie bei einer normalen Klasse erzeugt:

Moped m = new Moped("Henderson", "Z-2", 1919, 15);

Klassenstruktur eines Record

Das Kompilationsergebnis eines Record ist eine *.class-Datei, im obigen Beispiel Moped.class.

javap-Ausgabe des Record Moped.class

Untersucht man die kompilierte Klasse mit dem Disassembler javap, so zeigt sich, dass das Ergebnis eine final deklarierte, von java.lang.Record abgeleitete Klasse ist. Darüber hinaus wurden ein Konstruktor und in unserem Fall sieben Methoden erstellt. Die Ableitung von Record zeigt, dass Records nicht von anderen Klassen erben dürfen, gleichwohl können jedoch Interfaces implementiert werden.
Der vom Compiler erstellte Konstruktor dient zur Initialisierung der private und final deklarierten Felder.

private final String name, type;
private final int baujahr, ps;
public Moped(String name, String type, int baujahr, int ps) {
    this.name = name;
    this.type = type;
    this.baujahr = baujahr;
    this.ps = ps;
}

Es folgen vier lesende Accessor-Methoden (Getter) für den Zugriff auf die Variablen. Ihre Bezeichner entsprechen exakt denjenigen der Felder.
Die dann folgenden zwei Methoden dienen dem Vergleich von Objekten der Klasse. equals() liefert true, wenn bei zwei zu vergleichenden Instanzen die Werte aller Felder identisch sind, hashCode() liefert in diesem Fall beide Male einen identischen int-Wert. Auch die Möglichkeit zur String-Ausgabe eines Objektes der Klasse durch toString() wurde automatisch erzeugt. Sie liefert im obigen Fall der Klasse Moped:

Moped[name=Henderson, type=Z-2, baujahr=1919, ps=15]

Einen Record modifizieren

Ein Record kann ähnlich einer Klasse mehrere Konstruktoren besitzen. Allerdings darf die Anzahl der Argumente in den nachgeordneten Konstruktoren nicht größer sein als diejenige der Record-Signatur. Der kanonische Konstruktor muss dann mit this aufgerufen werden.

record Moped(String name, String type, int baujahr, int ps) {
    public Moped(String name, String type) {
        this(name, type, 0, 0);
    }
}

Zwar ist die zusätzliche Angabe von Instanzvariablen nicht statthaft, statische Variablen und Methoden, Instanzmethoden und das Überschreiben von Methoden aber durchaus.

//...
public final static int OLDTIMER = 1990;
//...
    @Override
    public String toString() {
        String s = "[name=" + name() + ", type=" + type() + ", baujahr="
                    + baujahr() + ", ps=" + ps() + "]";
        if (baujahr <= OLDTIMER) {
			return s + "  ->  Oldtimer";
        }
        return s;
    }
//...
Quellen

https://docs.oracle.com/en/java/javase/14/language/records.html

1) FUSSNOTE