Das "letzte" Schlüsselwort in Java

Das "letzte" Schlüsselwort in Java

1. Überblick

Während die Vererbung es uns ermöglicht, vorhandenen Code wiederzuverwenden, müssen wir manchmal aus verschiedenen Gründenset limitations on extensibility verwenden. Mit dem Schlüsselwortfinalkönnen wir genau das tun.

In diesem Tutorial sehen wir uns an, was das Schlüsselwortfinalfür Klassen, Methoden und Variablen bedeutet.

2. Final Klassen

Classes marked as final can’t be extended. Wenn wir uns den Code der Java-Kernbibliotheken ansehen, finden wir dort vielefinal-Klassen. Ein Beispiel ist die KlasseString.

Betrachten Sie die Situation, wenn wir die KlasseStringerweitern, eine ihrer Methoden überschreiben und alle Instanzen vonStringdurch die Instanzen unserer spezifischen UnterklasseStringersetzen können.

Das Ergebnis der Operationen überString Objekten wird dann unvorhersehbar. Und da die KlasseStringüberall verwendet wird, ist dies nicht akzeptabel. Aus diesem Grund wird die KlasseStringalsfinal markiert.

Jeder Versuch, von einerfinal-Klasse zu erben, führt zu einem Compilerfehler. Um dies zu demonstrieren, erstellen wir diefinal-KlasseCat:

public final class Cat {

    private int weight;

    // standard getter and setter
}

Und versuchen wir es zu erweitern:

public class BlackCat extends Cat {
}

Wir werden den Compilerfehler sehen:

The type BlackCat cannot subclass the final class Cat

Beachten Sie, dassthe final keyword in a class declaration doesn’t mean that the objects of this class are immutable. Wir können die Felder des Objekts vonCatfrei ändern:

Cat cat = new Cat();
cat.setWeight(1);

assertEquals(1, cat.getWeight());

Wir können es einfach nicht erweitern.

Wenn wir uns strikt an die Regeln für gutes Design halten, sollten wir eine Klasse sorgfältig erstellen und dokumentieren oder sie aus Sicherheitsgründen alsfinaldeklarieren. Beim Erstellen vonfinal-Klassen sollten wir jedoch vorsichtig sein.

Beachten Sie, dass das Erstellen einer Klassefinal bedeutet, dass kein anderer Programmierer sie verbessern kann. Stellen Sie sich vor, wir verwenden eine Klasse und haben keinen Quellcode dafür. Bei einer Methode liegt ein Problem vor.

Wenn die Klassefinal, ist, können wir sie nicht erweitern, um die Methode zu überschreiben und das Problem zu beheben. Mit anderen Worten, wir verlieren die Erweiterbarkeit, einer der Vorteile der objektorientierten Programmierung.

3. Final Methoden

Methods marked as final cannot be overridden. Wenn wir eine Klasse entwerfen und der Meinung sind, dass eine Methode nicht überschrieben werden sollte, können wir diese Methodefinal erstellen. Wir können auch vielefinal-Methoden in Java-Kernbibliotheken finden.

Manchmal müssen wir eine Klassenerweiterung nicht vollständig verbieten, sondern nur das Überschreiben einiger Methoden verhindern. Ein gutes Beispiel hierfür ist die KlasseThread. Es ist zulässig, sie zu erweitern und auf diese Weise eine benutzerdefinierte Thread-Klasse zu erstellen. Aber seineisAlive() Methoden sindfinal.

Diese Methode überprüft, ob ein Thread aktiv ist. Es ist aus vielen Gründen unmöglich, dieisAlive()-Methode korrekt zu überschreiben. Eine davon ist, dass diese Methode native ist. Native Code wird in einer anderen Programmiersprache implementiert und ist häufig spezifisch für das Betriebssystem und die Hardware, auf der er ausgeführt wird.

Erstellen wir eineDog-Klasse und machen ihresound()-Methodefinal:

public class Dog {
    public final void sound() {
        // ...
    }
}

Erweitern wir nun die KlasseDogund versuchen, die Methodesound()zu überschreiben:

public class BlackDog extends Dog {
    public void sound() {
    }
}

Wir werden den Compilerfehler sehen:

- overrides
com.example.finalkeyword.Dog.sound
- Cannot override the final method from Dog
sound() method is final and can’t be overridden

Wenn einige Methoden unserer Klasse von anderen Methoden aufgerufen werden, sollten wir in Betracht ziehen, die aufgerufenen Methodenfinal zu erstellen. Andernfalls kann das Überschreiben die Arbeit der Anrufer beeinträchtigen und zu überraschenden Ergebnissen führen.

Wenn unser Konstruktor andere Methoden aufruft, sollten wir diese Methoden aus dem oben genannten Grund generell alsfinal deklarieren.

Was ist der Unterschied zwischen dem Erstellen aller Methoden der Klassefinal und dem Markieren der Klasse selbstfinal? Im ersten Fall können wir die Klasse erweitern und neue Methoden hinzufügen.

Im zweiten Fall können wir das nicht tun.

4. Final Variablen

Variables marked as final can’t be reassigned. Sobald einefinal-Variable initialisiert wurde, kann sie nicht mehr geändert werden.

4.1. Final primitive Variablen

Deklarieren wir die Variablei, eines Grundelementsfinalund weisen ihm dann 1 zu.

Und lassen Sie uns versuchen, einen Wert von 2 zuzuweisen:

public void whenFinalVariableAssign_thenOnlyOnce() {
    final int i = 1;
    //...
    i=2;
}

Der Compiler sagt:

The final local variable i may already have been assigned

4.2. Final Referenzvariablen

Wenn wir eine Referenzvariable vonfinalhaben, können wir sie auch nicht neu zuweisen. Aberthis doesn’t mean that the object it refers to is immutable. Wir können die Eigenschaften dieses Objekts frei ändern.

Um dies zu demonstrieren, deklarieren wir die Referenzvariablecat vonfinalund initialisieren sie:

final Cat cat = new Cat();

Wenn wir versuchen, es neu zuzuweisen, wird ein Compilerfehler angezeigt:

The final local variable cat cannot be assigned. It must be blank and not using a compound assignment

Wir können jedoch die Eigenschaften der Instanz vonCatändern:

cat.setWeight(5);

assertEquals(5, cat.getWeight());

4.3. Final Felder

Final fields can be either constants or write-once fields. Um sie zu unterscheiden, sollten wir eine Frage stellen - würden wir dieses Feld einschließen, wenn wir das Objekt serialisieren würden? Wenn nein, ist es kein Teil des Objekts, sondern eine Konstante.

Beachten Sie, dass gemäß den Namenskonventionen Klassenkonstanten in Großbuchstaben geschrieben werden sollten, wobei die Komponenten durch Unterstriche („_“) voneinander getrennt sind:

static final int MAX_WIDTH = 999;

Beachten Sie, dassany final field must be initialized before the constructor completes.

Fürstatic final Felder bedeutet dies, dass wir sie initialisieren können:

  • bei Deklaration wie im obigen Beispiel gezeigt

  • im statischen Initialisierungsblock

Zum Beispiel bedeutetfinal Felder, dass wir sie initialisieren können:

  • nach erklärung

  • im Instanzinitialisierungsblock

  • im Konstruktor

Andernfalls gibt der Compiler einen Fehler aus.

4.4. Final Argumente

Das Schlüsselwortfinaldarf auch vor Methodenargumenten stehen. A final argument can’t be changed inside a method:

public void methodWithFinalArguments(final int x) {
    x=1;
}

Die obige Zuweisung verursacht den Compilerfehler:

The final local variable x cannot be assigned. It must be blank and not using a compound assignment

5. Fazit

In diesem Artikel haben wir erfahren, was das Schlüsselwortfinalfür Klassen, Methoden und Variablen bedeutet. Obwohl wir das Schlüsselwortfinalin unserem internen Code möglicherweise nicht häufig verwenden, ist es möglicherweise eine gute Entwurfslösung.

Wie immer finden Sie den vollständigen Code für diesen Artikel inGitHub project.