Unterschiede zwischen Final, Final und Finalize in Java

1. Überblick

In diesem Tutorial erhalten Sie einen Überblick über drei Java-Schlüsselwörter:

Während diese Schlüsselwörter einander ähneln, haben beide in Java eine sehr unterschiedliche Bedeutung. Wir werden den Zweck jedes einzelnen kennen lernen und einige Beispiele durch ein wenig Code sehen.

2. final Schlüsselwort

Werfen wir zunächst einen Blick auf das Schlüsselwort final , wo und warum es verwendet wird.

  • Das Schlüsselwort final kann auf Deklarationen von Klassen, Methoden, Feldern, Variablen und Methodenparametern angewendet werden. **

  • Es hat jedoch nicht die gleiche Wirkung bei jedem von ihnen ** :

  • Das Erstellen einer Klasse final bedeutet, dass eine Erweiterung nicht möglich ist

Klasse ** Das Hinzufügen von final zu einer Methode bedeutet, dass das Überschreiben nicht möglich ist

diese Methode ** Schließlich final vor ein Feld, eine Variable oder ein

Parameter bedeutet, dass die einmal zugewiesene Referenz nicht mehr geändert werden kann (wenn sich die Referenz jedoch auf ein veränderliches Objekt bezieht, kann sich der interne Status ändern, obwohl er endgültig ist)

Einen ausführlichen Artikel zum Schlüsselwort final finden Sie unter hier .

Sehen wir uns anhand einiger Beispiele an, wie das Schlüsselwort final funktioniert.

2.1. final Felder, Parameter und Variablen

Erstellen wir eine Parent -Klasse mit zwei _int -Feldern, einem final_ -Feld und einem regulären, nicht endgültigen Feld:

public class Parent {

    int field1 = 1;
    final int field2 = 2;

    Parent() {
        field1 = 2;//OK
        field2 = 3;//Compilation error
    }

}

Wie wir sehen, verbietet uns der Compiler, field2 einen neuen Wert zuzuweisen.

Fügen wir nun eine Methode mit einem regulären und einem letzten Argument hinzu:

    void method1(int arg1, final int arg2) {
        arg1 = 2;//OK
        arg2 = 3;//Compilation error
    }

Ähnlich wie bei Feldern ist es nicht möglich, arg2 etwas zuzuweisen, da es als final deklariert ist.

Wir können jetzt eine zweite Methode hinzufügen, um zu veranschaulichen, wie dies mit lokalen Variablen funktioniert:

    void method2() {
        final int localVar = 2;//OK
        localVar = 3;//Compilation error
    }

Nichts Unerwartetes passiert, der Compiler lässt localVar nach seiner ersten Zuweisung keinen neuen Wert zuweisen

2.2. final Methode

Nehmen wir nun an, wir machen method2 final und erstellen eine Unterklasse von Parent , sagen wir Child , in der wir versuchen, beide Superklassenmethoden zu überschreiben:

public class Child extends Parent {

    @Override
    void method1(int arg1, int arg2) {
       //OK
    }

    @Override
    final void method2() {
       //Compilation error
    }

}

Wie wir sehen, gibt es kein Problem beim Überschreiben von method1 () , aber beim Versuch, method2 () zu überschreiben, wird ein Kompilierungsfehler angezeigt.

2.3. final Klasse

Und schließlich machen wir die Child -Klasse final und versuchen, eine Unterklasse davon zu erstellen, GrandChild :

public final class Child extends Parent {
   //...
}
public class GrandChild extends Child {
   //Compilation error
}

Wieder klagt der Compiler. Die Child -Klasse ist final und daher nicht erweiterbar.

3. endlicher Block

Der finally -Block ist ein optionaler Block, der mit einer try/catch -Anweisung verwendet werden kann. In diesem Block enthalten wir Code, der nach der ____try/catch -Struktur ausgeführt werden soll, unabhängig davon, ob eine Ausnahme ausgelöst wird oder nicht.

Es ist sogar möglich, es mit dem try -Block ohne catch -Block zu verwenden, vorausgesetzt, wir enthalten einen finally -Block. Der Code wird dann nach dem try oder nachdem eine Ausnahme ausgelöst wurde, ausgeführt.

Wir haben einen ausführlichen Artikel zur Ausnahmebehandlung in Java hier .

Lassen Sie uns nun in einem kurzen Beispiel einen finally -Block demonstrieren. Wir erstellen eine Dummy-Methode main () mit einer try/catch/finally -Struktur:

public static void main(String args[]) {
    try {
        System.out.println("Execute try block");
        throw new Exception();
    } catch (Exception e) {
        System.out.println("Execute catch block");
    } finally {
        System.out.println("Execute finally block");
    }
}

Wenn wir diesen Code ausführen, wird Folgendes ausgegeben:

Execute try block
Execute catch block
Execute finally block

Ändern wir nun die Methode, indem Sie den catch-Block entfernen (und fügen Sie der Signatur throws Exception hinzu):

public static void main(String args[]) throws Exception {
    try {
        System.out.println("Execute try block");
        throw new Exception();
    } finally {
        System.out.println("Execute finally block");
    }
}

Die Ausgabe ist jetzt:

Execute try block
Execute finally block

Wenn wir nun die Anweisung throw new Exception () entfernen, können wir beobachten, dass die Ausgabe gleich bleibt. Unser final -Block wird jedes Mal ausgeführt.

4. finalize -Methode

Und schließlich ist die finalize -Methode eine geschützte Methode, die in der Klasse https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#finalize-- [Object definiert ist. Es wird vom Garbage Collector für Objekte aufgerufen, die nicht mehr referenziert und für die Garbage Collection ausgewählt wurden.

Wie jede andere nicht endgültige Methode können wir diese Methode überschreiben, um das Verhalten zu definieren, das ein Objekt haben muss, wenn es vom garbage collector erfasst wird.

Einen ausführlichen Artikel über die finalize -Methode finden Sie hier: hier .

Sehen wir uns ein Beispiel dafür an, wie es funktioniert. Wir verwenden System.gc () , um den JVM zum Auslösen der garbage collection vorzuschlagen:

    @Override
    protected void finalize() throws Throwable {
        System.out.println("Execute finalize method");
        super.finalize();
    }
    public static void main(String[]args) throws Exception {
        FinalizeObject object = new FinalizeObject();
        object = null;
        System.gc();
        Thread.sleep(1000);
    }

In diesem Beispiel überschreiben wir die finalize () - Methode in unserem Objekt und erstellen eine main () - Methode, die unser Objekt instantiiert und die Referenz sofort löscht, indem Sie die erstellte Variable auf null setzen.

Danach rufen wir System.gc () auf, um den garbage collector auszuführen (zumindest erwarten wir, dass er ausgeführt wird) und warten eine Sekunde (um sicherzustellen, dass JVM nicht heruntergefahren wird, bevor garbage collector die Möglichkeit hat, aufzurufen finalize () Methode).

Die Ausgabe dieser Codeausführung sollte lauten:

Execute finalize method

Beachten Sie, dass es als schlechte Praxis angesehen wird, die finalize () -Methode zu überschreiben, da ihre Ausführung von garbage collection abhängt, die in der Hand des JVM liegt. Außerdem wurde diese Methode seit Java 9 deprecated .

5. Schlussfolgerung

In diesem Artikel haben wir kurz die Unterschiede zwischen den drei Java-ähnlichen Suchbegriffen behandelt:

Der vollständige Code des Artikels kann gefunden werden https://github.com/eugenp/tutorials/tree/master/core-java-lang GitHub.]