web-dev-qa-db-fra.com

Java Méthode `final`: que promet-il?

Dans une classe Java, une méthode peut être définie comme étant final, pour indiquer que cette méthode ne peut pas être remplacée:

public class Thingy {
    public Thingy() { ... }
    public int operationA() {...}
    /** this method does @return That and is final. */
    public final int getThat() { ...}
}

C'est clair, et cela peut être utile pour se protéger contre les dérogations accidentelles, voire les performances - mais ce n'est pas ma question.

Ma question est la suivante: d’un OOP point de vue, j’ai compris qu’en définissant une méthode final le concepteur de la classe promet cette méthode fonctionnera toujours comme décrit ou sous-entendu. Mais cela peut souvent être en dehors de l’influence de l’auteur de la classe, si ce que fait la méthode est plus compliqué que de simplement fournir un propriété .

La contrainte syntaxique est claire pour moi, mais quelle est l'implication dans le sens OOP? Est-ce que final est utilisé correctement dans ce sens par la plupart des auteurs de classes?

Quel genre de "contrat" ​​une méthode final promet-elle?

133
towi

Comme mentionné, final est utilisé avec une méthode Java pour indiquer que la méthode ne peut pas être remplacée (pour la portée de l'objet) ni masquée (pour la statique). Ceci permet à l'original développeur pour créer une fonctionnalité qui ne peut pas être modifiée par les sous-classes, et c’est toute la garantie qu’il offre.

Cela signifie que si la méthode s'appuie sur d'autres composants personnalisables tels que des champs/méthodes non publics, les fonctionnalités de la méthode finale peuvent toujours être personnalisables. C'est bien, car (avec le polymorphisme) cela permet une personnalisation partielle.

Il existe un certain nombre de raisons pour empêcher que quelque chose soit personnalisable, notamment:

  • Performance - Certains compilateurs peuvent analyser et optimiser le fonctionnement, en particulier celui sans effets secondaires.

  • Obtention des données encapsulées - Observez les objets immuables dont les attributs sont définis au moment de la construction et ne doivent jamais être modifiés. Ou une valeur calculée dérivée de ces attributs. Un bon exemple est la classe Java String.

  • Fiabilité et contrat - Les objets sont composés de primitives (int, char, double, etc.) et/ou d’autres objets. Toutes les opérations applicables à ces composants ne doivent pas nécessairement être applicables ou même logiques lorsqu'elles sont utilisées dans le plus grand objet. Des méthodes avec le modificateur final peuvent être utilisées pour s'assurer que. La classe Counter est un bon exemple.


public class Counter {
    private int counter = 0;

    public final int count() {
        return counter++;
    }

    public final int reset() {
        return (counter = 0);
    }
}

Si la méthode public final int count() n'est pas final, nous pouvons faire quelque chose comme ceci:

Counter c = new Counter() {   
    public int count() {
        super.count();   
        return super.count();   
    } 
}

c.count(); // now count 2

Ou quelque chose comme ça:

Counter c = new Counter() {
    public int count() {
        int lastCount = 0;
        for (int i = super.count(); --i >= 0; ) {
            lastCount = super.count();
        }

        return lastCount;
    }
}

c.count(); // Now double count
144
NawaMan

Quel type de "contrat" ​​une méthode finale promet-elle?

Envisagez-le dans l'autre sens: toute méthode non finale fournit la garantie implicite que vous pouvez la remplacer par votre propre implémentation et que la classe fonctionnera toujours comme prévu. Lorsque vous ne pouvez pas garantir que votre classe prend en charge l'écriture d'une méthode, vous devez la rendre définitive.

24
josefx

Tout d’abord, vous pouvez marquer les classes non abstraites final ainsi que les champs et les méthodes. De cette façon, toute la classe ne peut pas être sous-classée. Donc, le comportement de la classe sera corrigé.

Je conviens que les méthodes de marquage final ne garantissent pas que leur comportement sera le même dans les sous-classes si ces méthodes appellent des méthodes non finales. Si le comportement doit effectivement être corrigé, il faut y parvenir par convention et par une conception soignée. Et n'oubliez pas de le comprendre dans javadoc! (Documentation Java)

Dernier point mais non le moindre, le mot clé final a un rôle très important dans Java Modèle de mémoire (JMM). Il est garanti par JMM que pour obtenir la visibilité des champs final vous n'avez pas besoin d'une synchronisation appropriée.

class A implements Runnable {
  final String caption = "Some caption";                           

  void run() {
    // no need to synchronize here to see proper value of final field..
    System.out.println(caption);
  }
}  
8
Victor Sorokin

Non, ce n'est pas en dehors de l'influence de l'auteur de la classe. Vous ne pouvez pas le remplacer dans votre classe dérivée, il fera donc ce que l'auteur de la classe de base avait prévu.

http://download.Oracle.com/javase/tutorial/Java/IandI/final.html

Il convient de noter la partie où elle suggère que les méthodes appelées à partir de constructeurs devraient être final.

0
Brian Roach

Je ne suis pas sûr que vous puissiez affirmer l'utilisation de "final" et son incidence sur le contrat de conception global du logiciel. Vous êtes assuré qu'aucun développeur ne peut ignorer cette méthode et annuler son contrat de cette façon. D'autre part, la méthode finale peut s'appuyer sur des variables de classe ou d'instance dont les valeurs sont définies par des sous-classes, et peut appeler d'autres méthodes de classe qui are sont remplacées. Donc, final est tout au plus une garantie très faible.

0
Jim Ferrans