final

Das Schlüsselwort final markiert eine (benannte) Einheit (Variable, Methode oder Klasse), der nur ein einziges mal ein Wert (o.ä.) zugewiesen werden kann. Dies hat in unterschiedlichen Kontexten unterschiedliche weitere Auswirkungen …

Finale Variablen

Finalen Variablen (also Variablen, die als final markiert sind), kann nur ein mal ein Wert zugewiesen und dann nicht mehr geändert werden, d.h. eine primitive int-Variable number

final int number = 42;

…wird immer den Wert 42 behalten (solange sie existiert). Der Wert einer Variablen mit komplexem Datentyp ist die Adresse des zugewiesenen Objektes. Dadurch wird der Wert einer User-Variable user

final User user = new User("Foo Bar", "foo.bar@example.org");

…immer die Referenz auf genau dieses User-Objekt sein.

💬 Finale Variablen können auch noch nach der Deklaration einen Wert erhalten, aber eben nur ein mal!

Im folgenden Beispiel kann der Name des Users nur einmal (bei Instanziierung der Klasse bzw. Erzeugung eines Objektes) gesetzt werden. Der Wert dieser Instanzvariable kann dann für dieses Objekt nicht mehr geändert werden. Die Instanziierung (Aufruf des Konstruktors) ist der letzte mögliche Zeitpunkt zum Setzen eines Wertes für dieses finale Attribut!

public class User {

  private final String name;

  public User(String name){
    this.name = name;
  }

}

Finale Methoden

⚠️ Dieser Abschnitt setzt Kenntnisse zu Vererbung voraus.

Auf Methoden hat die Verwendung von final eine etwas andere Wirkung, die sich semantsch aber gut anschließt: Finale Methoden können nicht überschrieben werden.

public final void someMethod(){
  /*
  * Diese Methode kann in einer erweiternden (erbenden)
  * Klasse nicht überschrieben werden!
  */
}

Das ist dann eine gute Idee, wenn die konkrete Implementation dieser Methode wichtig für die Integrität der Klasse ist. Das ist besonders beim Design von 👉 APIs relevant.

Finale Klassen

⚠️ Dieser Abschnitt setzt Kenntnisse zu Vererbung voraus.

Sehr ähnlich wie bei Methoden wirkt sich final bei Klassen aus: Finale Klassen können nicht erweitert werden.

final class ImmutableClass {
  // Diese Klasse kann nicht erweitert werden!
}

Dies wird dann verwendet, wenn die Klasse nicht dafür gedacht ist, erweitert zu werden. Dafür kann es unterschiedliche Gründe geben, die z.B. hier oder hier nachzulesen sind. Diese Entscheidung ist besonders beim Design von 👉 APIs relevant.

Konstanten in Java

Konstanten sind Variablen mit unveränderbarem Wert. Also Variablen, die nicht variabel sind und deren Wert nur ein einziges mal gesetzt werden kann. Java hat kein eigenes Schlüsselwort zum definieren von Konstanten (wie etwa const in anderen Sprachen). Stattdessen kann das bereits vorhandene Schlüsselwort final genutzt werden, um finale Variablen zu definieren - die ja im Grunde nichts anderes sind.

Klassischerweise werden Konstanten dazu genutzt, unveränderbare Eigenschaften von Klassen zu repräsentieren. Es bietet sich in Java deshalb die zusätzliche Verwendung von static an, um die “Konstante” an die Klasse zu binden. Die folgende Ausführung ist durchaus der Standard und sehr oft genau so anzutreffen:

// könnten auch "public" sein!
private static final int THIS_IS_A_PRIVATE_CONSTANT = 2;
private static final double PI = 3.142;

💬 Mit den Zugriffsmodfizierern public, private, (…) können solche “Konstanten” öffentlich oder nur beschränkt sichtbar gemacht werden.

Den Java Naming Conventions folgend werden solche “Konstanten” wie oben zu sehen im UPPERCASE_MIT_UNTERSTRICHEN geschrieben!

⚠️ Obwohl der Wert einer “Konstanten” (static final) unveränderbar ist, kann das von einer Konstante mit komplexem Datentyp referenzierte Objekt selbst verändert werden, indem sich Eigenschaften dieses Objektes ändern! Beispiel: private static final User STANDARD_USER = new User("Max Mustermann"); … und dann … STANDARD_USER.setName("Maximiliane Muserfrau");. Die Konstante referenziert dann noch immer das selbe Objekt!