Différences entre Final, Finally et Finalize en Java

Différences entre Final, Finally et Finalize en Java

1. Vue d'ensemble

Dans ce didacticiel, nous allons présenter trois mots clés Java:final, finally andfinalize.

Bien que ces mots clés se ressemblent, chacun a une signification très différente en Java. Nous apprendrons le but de chacun d'eux et verrons quelques exemples à travers un peu de code.

2. Mot-cléfinal

Examinons d'abord le mot cléfinal, où l'utiliser et pourquoi. We can apply the final keyword to class, method, field, variable and method parameter declarations.

It doesn’t have the same effect on each of them though:

  • Créer une classefinal signifie qu'il ne sera pas possible d'étendre cette classe

  • L'ajout definal à une méthode signifie qu'il ne sera pas possible de remplacer cette méthode

  • Enfin, mettrefinal devant un champ, une variable ou un paramètre signifie qu'une fois la référence affectée, elle ne peut pas être modifiée (cependant, si la référence est à un objet mutable, son état interne peut changer malgré étant définitif)

Un article détaillé sur le mot-cléfinal peut être trouvéhere.

Voyons comment le mot-cléfinal fonctionne à travers quelques exemples.

2.1. Champs, paramètres et variablesfinal

Créons une classeParent avec deux champsint , unfinal un et un non final normal:

public class Parent {

    int field1 = 1;
    final int field2 = 2;

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

}

Comme nous pouvons le voir, le compilateur nous interdit d'attribuer une nouvelle valeur àfield2.

Ajoutons maintenant une méthode avec un argument normal et un argument final:

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

Comme pour les champs, il n’est pas possible d’attribuer quelque chose àarg2 car il est déclaré définitif.

Nous pouvons maintenant ajouter une deuxième méthode pour illustrer son fonctionnement avec des variables locales:

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

Rien de surprenant ne se produit, le compilateur ne nous laisse pas attribuer une nouvelle valeur àlocalVar après sa première affectation.

2.2. Méthodefinal

Supposons maintenant que nous rendionsmethod2 final et que nous créions une sous-classe deParent, disonsChild, dans laquelle nous essayons de remplacer ses deux méthodes de superclasse:

public class Child extends Parent {

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

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

}

Comme nous pouvons le voir, il n'y a pas de problème avec le remplacement demethod1(), mais nous obtenons une erreur de compilation en essayant de remplacermethod2().

2.3. Classefinal

Et enfin, rendons la classeChild finale et essayons d'en créer une sous-classe,GrandChild:

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

Encore une fois, le compilateur se plaint. La classeChild est définitive et donc impossible à étendre.

3. Blocfinally

Le blocfinally est un bloc facultatif à utiliser avec une instructiontry/catch. In this block, we include code to execute after the try/catch structure, whether an exception is thrown or not.

Il est même possible de l’utiliser avec le bloctry sans aucun bloccatch à condition d’inclure un blocfinally. Le code sera alors exécuté après lestry ou après qu'une exception soit levée.

Nous avons un article détaillé sur la gestion des exceptions dans Javahere.

Voyons maintenant un blocfinally dans un court exemple. Nous allons créer une méthode facticemain() avec une structuretry/catch/finally:

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");
    }
}

Si nous exécutons ce code, il affichera les éléments suivants:

Execute try block
Execute catch block
Execute finally block

Modifions maintenant la méthode en supprimant le bloc catch (et en ajoutantthrows Exception à la signature):

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");
    }
}

La sortie est maintenant:

Execute try block
Execute finally block

Si nous supprimons maintenant l'instructionthrow new Exception(), nous pouvons observer que la sortie reste la même. L'exécution de notre blocfinally se produit à chaque fois.

4. Méthodefinalize

Et enfin, la méthodefinalize est une méthode protégée, définie dans lesObject class. It’s called by the garbage collector on objects that aren’t referenced anymore and have been selected for garbage collection.

Comme toute autre méthode non finale, nous pouvons remplacer cette méthode pour définir le comportement qu'un objet doit avoir lorsqu'il est collecté par lesgarbage collector.

Encore une fois, un article détaillé couvrant la méthodefinalize peut être trouvéhere.

Voyons un exemple de son fonctionnement. Nous utiliseronsSystem.gc() pour suggérer lesJVM pour déclenchergarbage collection:

    @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);
    }

Dans cet exemple, nous remplaçons la méthodefinalize() dans notre objet et créons une méthodemain() qui instancie notre objet et supprime immédiatement la référence en définissant la variable créée surnull.

Après cela, nous appelonsSystem.gc() pour exécuter legarbage collector (au moins nous nous attendons à ce qu'il s'exécute) et attendons une seconde (juste pour nous assurer que leJVM ne s'arrête pas avantgarbage collector a la possibilité d'appeler la méthodefinalize()).

Le résultat de cette exécution de code devrait être:

Execute finalize method

Notez qu'il est considéré comme une mauvaise pratique de remplacer la méthodefinalize() car son exécution dépend degarbage collection qui est entre les mains desJVM. Plus, this method has been deprecated since Java 9.

5. Conclusion

Dans cet article, nous avons brièvement discuté des différences entre les trois mots clés identiques à Java:final, finally etfinalize.

Le code complet de l'article se trouveover on GitHub.