Différences entre Final, Enfin et Finaliser en Java

1. Vue d'ensemble

Dans ce tutoriel, nous allons prendre un aperçu de trois mots-clés Java: final, enfin et finaliser.

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

2. mot-clé final

Jetons d'abord un coup d'œil au mot-clé final , où l'utiliser et pourquoi. Nous pouvons appliquer le mot-clé final aux déclarations de paramètres de classe, de méthode, de champ, de variable et de méthode.

Cela n'a cependant pas le même effet sur chacun d'eux :

  • Rendre une classe finale signifie qu'il ne sera pas possible d'étendre cette classe
  • L'ajout de final à une méthode signifie qu'il ne sera pas possible de remplacer cette méthode
  • Enfin, mettre final devant un champ, une variable ou un paramètre signifie qu'une fois que la référence a été affectée, elle ne peut pas être modifiée (cependant, si la référence est à un objet mutable, son état interne pourrait changer bien qu'il soit définitif)

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

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

2.1. Champs, paramètres et variables finaux

Créons une classe Parent avec deux champs int , un dernier et un normal non final:

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é final.

Nous pouvons maintenant ajouter une deuxième méthode pour illustrer comment cela fonctionne 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 assignation.

2.2. Méthode finale

Supposons maintenant que nous rendions la méthode 2 finale et que nous créions une sous-classe de Parent , disons Child , 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 la substitution de method1 () , mais nous obtenons une erreur de compilation en essayant de remplacer method2 () .

2.3. Classe finale

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

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

Une fois de plus, le compilateur se plaint. La classe Enfant est définitive et donc impossible à prolonger.

3. enfin bloquer

Le bloc finally est un bloc facultatif à utiliser avec une instruction try / catch . Dans ce bloc, nous incluons du code à exécuter après la structure try / catch , qu'une exception soit levée ou non .

Il est même possible de l'utiliser avec le bloc try sans aucun bloc catch à condition d'inclure un bloc finally . Le code sera ensuite exécuté après l' essai ou après qu'une exception est levée.

Nous avons ici un article détaillé sur la gestion des exceptions en Java.

Maintenant, démontrons un bloc finally dans un court exemple. Nous allons créer une méthode factice main () avec une structure try / 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 ce qui suit:

Execute try block Execute catch block Execute finally block

Modifions maintenant la méthode en supprimant le bloc catch (et ajoutons throws 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' instruction throw new Exception () , nous pouvons observer que la sortie reste la même. Notre exécution de bloc final se produit à chaque fois.

4. Finaliser Méthode

Et enfin, la méthode finalize est une méthode protégée, définie dans la classe Object. Il est appelé par le garbage collector sur des objets qui ne sont plus référencés et qui ont été sélectionnés pour le 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 le garbage collector .

Encore une fois, un article détaillé couvrant la méthode de finalisation est disponible ici.

Voyons un exemple de son fonctionnement. Nous utiliserons System.gc () pour suggérer à la JVM de déclencher le garbage 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 redéfinissons la méthode finalize () dans notre objet et créons une méthode main () qui instancie notre objet et supprime immédiatement la référence en définissant la variable créée sur null .

After that, we call System.gc() to run the garbage collector (at least we expect it to run) and wait for a second (just to ensure that the JVM doesn't shut down before garbage collector has the chance to call finalize() method).

The output of this code execution should be:

Execute finalize method

Note that it's considered bad practice to override finalize() method as its execution depends on garbage collection which is in the hand of the JVM. 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 Java: final, finally et finalize .

Le code complet de l'article est disponible à l'adresse over sur GitHub.