Le mot-clé "final" en Java

Le mot clé "final" en Java

1. Vue d'ensemble

Alors que l'héritage nous permet de réutiliser le code existant, nous avons parfois besoin deset limitations on extensibility pour diverses raisons; le mot-cléfinal nous permet de faire exactement cela.

Dans ce didacticiel, nous allons examiner ce que signifie le mot-cléfinal pour les classes, les méthodes et les variables.

2. Final Classes

Classes marked as final can’t be extended. Si nous regardons le code des bibliothèques Java Core, nous y trouverons de nombreuses classesfinal. Un exemple est la classeString.

Considérez la situation si nous pouvons étendre la classeString, remplacer l'une de ses méthodes et remplacer toutes les instancesString par les instances de notre sous-classeString spécifique.

Le résultat des opérations sur les objetsString deviendra alors imprévisible. Et étant donné que la classeString est utilisée partout, c'est inacceptable. C’est pourquoi la classeString est marquée commefinal.

Toute tentative d'hériter d'une classefinal provoquera une erreur du compilateur. Pour illustrer cela, créons la classefinalCat:

public final class Cat {

    private int weight;

    // standard getter and setter
}

Et essayons de l’étendre:

public class BlackCat extends Cat {
}

Nous verrons l’erreur du compilateur:

The type BlackCat cannot subclass the final class Cat

Notez quethe final keyword in a class declaration doesn’t mean that the objects of this class are immutable. Nous pouvons modifier librement les champs de l'objetCat:

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

assertEquals(1, cat.getWeight());

Nous ne pouvons tout simplement pas l’étendre.

Si nous suivons strictement les règles de bonne conception, nous devons créer et documenter une classe soigneusement ou la déclarerfinal pour des raisons de sécurité. Cependant, nous devons faire preuve de prudence lors de la création des classesfinal.

Notez que créer une classefinal signifie qu'aucun autre programmeur ne peut l'améliorer. Imaginez que nous utilisons une classe et que nous n’avons pas le code source pour celle-ci, et qu’il y a un problème avec une méthode.

Si la classe estfinal,, nous ne pouvons pas l'étendre pour remplacer la méthode et résoudre le problème. En d'autres termes, nous perdons l'extensibilité, l'un des avantages de la programmation orientée objet.

3. Final Méthodes

Methods marked as final cannot be overridden. Lorsque nous concevons une classe et que nous estimons qu’une méthode ne doit pas être remplacée, nous pouvons rendre cette méthodefinal. Nous pouvons également trouver de nombreuses méthodesfinal dans les bibliothèques Java Core.

Parfois, il n’est pas nécessaire d’interdire complètement une extension de classe, mais seulement d’empêcher le dépassement de certaines méthodes. La classeThread en est un bon exemple. Il est légal de l’étendre et de créer ainsi une classe de thread personnalisée. Mais ses méthodesisAlive() sontfinal.

Cette méthode vérifie si un thread est en vie. Il est impossible de remplacer correctement la méthodeisAlive() pour de nombreuses raisons. L'un d'eux est que cette méthode est native. Le code natif est implémenté dans un autre langage de programmation et est souvent spécifique au système d'exploitation et au matériel sur lequel il s'exécute.

Créons une classeDog et rendons sa méthodesound()final:

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

Étendons maintenant la classeDog et essayons de remplacer sa méthodesound():

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

Nous verrons l’erreur du compilateur:

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

Si certaines méthodes de notre classe sont appelées par d'autres méthodes, nous devrions envisager de rendre les méthodes appeléesfinal. Sinon, les ignorer peut affecter le travail des appelants et provoquer des résultats surprenants.

Si notre constructeur appelle d'autres méthodes, nous devons généralement déclarer ces méthodesfinal pour la raison ci-dessus.

Quelle est la différence entre faire toutes les méthodes de la classefinal et marquer la classe elle-mêmefinal? Dans le premier cas, nous pouvons étendre la classe et y ajouter de nouvelles méthodes.

Dans le second cas, nous ne pouvons pas faire cela.

4. VariablesFinal

Variables marked as final can’t be reassigned. Une fois qu’une variablefinal est initialisée, elle ne peut pas être modifiée.

4.1. Variables primitivesFinal

Déclarons une variable primitivefinali, puis affectons-lui 1.

Et essayons de lui attribuer une valeur de 2:

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

Le compilateur dit:

The final local variable i may already have been assigned

4.2. Variables de référenceFinal

Si nous avons une variable de référencefinal, nous ne pouvons pas non plus la réaffecter. Maisthis doesn’t mean that the object it refers to is immutable. Nous pouvons changer les propriétés de cet objet librement.

Pour le démontrer, déclarons la variable de référencefinalcat et initialisons-la:

final Cat cat = new Cat();

Si nous essayons de le réaffecter, nous verrons une erreur de compilation:

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

Mais nous pouvons changer les propriétés de l'instanceCat:

cat.setWeight(5);

assertEquals(5, cat.getWeight());

4.3. ChampsFinal

Final fields can be either constants or write-once fields. Pour les distinguer, nous devons nous poser une question - inclurions-nous ce champ si nous devions sérialiser l'objet? Si non, alors cela ne fait pas partie de l’objet, mais une constante.

Notez que, conformément aux conventions de dénomination, les constantes de classe doivent être majuscules, avec des composants séparés par des caractères de soulignement («_»):

static final int MAX_WIDTH = 999;

Notez queany final field must be initialized before the constructor completes.

Pour les champsstatic final, cela signifie que nous pouvons les initialiser:

  • sur déclaration comme indiqué dans l'exemple ci-dessus

  • dans le bloc initialiseur statique

Par exemple les champsfinal, cela signifie que nous pouvons les initialiser:

  • sur déclaration

  • dans le bloc d'initialisation d'instance

  • dans le constructeur

Sinon, le compilateur nous donnera une erreur.

4.4. ArgumentsFinal

Le mot cléfinal est également autorisé à placer avant les arguments de méthode. A final argument can’t be changed inside a method:

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

L'affectation ci-dessus provoque l'erreur du compilateur:

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

5. Conclusion

Dans cet article, nous avons appris ce que signifie le mot-cléfinal pour les classes, les méthodes et les variables. Bien que nous n'utilisions pas souvent le mot-cléfinal dans notre code interne, cela peut être une bonne solution de conception.

Comme toujours, le code complet de cet article se trouve dans lesGitHub project.