web-dev-qa-db-fra.com

Arguments finaux dans les méthodes d'interface - à quoi ça sert?

En Java, il est parfaitement légal de définir des arguments final dans les méthodes d'interface et de ne pas obéir à cela dans la classe d'implémentation, par exemple:

public interface Foo {
    public void foo(int bar, final int baz);
}

public class FooImpl implements Foo {

    @Override
    public void foo(final int bar, int baz) {
        ...
    }
}

Dans l'exemple ci-dessus, bar et baz ont les définitions final opposées dans la classe VS l'interface.

De la même manière, aucune restriction final n'est appliquée lorsqu'une méthode de classe en étend une autre, que ce soit abstract ou non.

Alors que final a une valeur pratique à l'intérieur du corps de la méthode de classe, y a-t-il un point spécifiant final pour les paramètres de la méthode d'interface?

182
mindas

Il ne semble pas y avoir d'intérêt. Selon la Java Language Specification 4.12.4 :

La déclaration d'une variable finale peut servir de documentation utile que sa valeur ne changera pas et peut aider à éviter les erreurs de programmation.

Cependant, un modificateur final sur un paramètre de méthode n'est pas mentionné dans les règles de correspondance des signatures des méthodes substituées, et il n'a aucun effet sur l'appelant, uniquement dans le corps d'une implémentation . De plus, comme l'a noté Robin dans un commentaire, le modificateur final sur un paramètre de méthode n'a aucun effet sur le code d'octet généré. (Ce n'est pas vrai pour les autres utilisations de final.)

96
Ted Hopp

Certains IDE copient la signature de la méthode abstraite/interface lors de l'insertion d'une méthode d'implémentation dans une sous-classe.

Je ne pense pas que cela fasse une différence pour le compilateur.

EDIT: Bien que je pense que cela était vrai dans le passé, je ne pense pas que les IDE actuels le font plus.

23
Peter Lawrey

Les annotations finales des paramètres de méthode ne sont toujours pertinentes que pour l'implémentation de la méthode, jamais pour l'appelant. Par conséquent, il n'y a aucune raison réelle de les utiliser dans les signatures de méthode d'interface. À moins que vous ne vouliez suivre la même norme de codage cohérente, qui nécessite des paramètres de méthode finaux, dans toutes les signatures de méthode. Alors c'est bien de pouvoir le faire.

17
jmg

Mise à jour: La réponse originale ci-dessous a été écrite sans bien comprendre la question et ne répond donc pas directement à la question :) Néanmoins, il doit être informatif pour ceux qui cherchent à comprendre l'utilisation générale du mot-clé final.

Quant à la question, je voudrais citer mon propre commentaire d'en bas.

Je pense que vous n'êtes pas obligé d'implémenter la finalité d'un argument pour vous laisser libre de décider s'il doit être final ou non dans votre propre implémentation.

Mais oui, cela semble plutôt étrange que vous puissiez le déclarer final dans l'interface, mais l'avoir non final dans l'implémentation. Cela aurait été plus logique si:

a.final le mot clé n'était pas autorisé pour les arguments de la méthode d'interface (abstraite) (mais vous pouvez l'utiliser dans l'implémentation), ou
b. déclarer un argument comme final dans l'interface le forcerait à être déclaré final dans l'implémentation (mais pas forcé pour les non finales).


Je peux penser à deux raisons pour lesquelles une signature de méthode peut avoir des paramètres final: Beans et Objects ( En fait, ils sont à la fois la même raison, mais des contextes légèrement différents. )

Objets:

public static void main(String[] args) {
    StringBuilder cookingPot = new StringBuilder("Water ");
    addVegetables(cookingPot);
    addChicken(cookingPot);
    System.out.println(cookingPot.toString());
    // ^--- OUTPUT IS: Water Carrot Broccoli Chicken ChickenBroth 
    //      We forgot to add cauliflower. It went into the wrong pot.
}

private static void addVegetables(StringBuilder cookingPot) {
    cookingPot.append("Carrot ");
    cookingPot.append("Broccoli ");
    cookingPot = new StringBuilder(cookingPot.toString());
    //   ^--- Assignment allowed...
    cookingPot.append("Cauliflower ");
}

private static void addChicken(final StringBuilder cookingPot) {
    cookingPot.append("Chicken ");
    //cookingPot = new StringBuilder(cookingPot.toString());
    //     ^---- COMPILATION ERROR! It is final.
    cookingPot.append("ChickenBroth ");
}

Le mot clé final garantit que nous ne créerons pas accidentellement un nouveau pot de cuisson local en affichant une erreur de compilation lorsque nous avons tenté de le faire. Cela a garanti que le bouillon de poulet soit ajouté à notre marmite de cuisson d'origine obtenue par la méthode addChicken. Comparez cela à addVegetables où nous avons perdu le chou-fleur car il l'a ajouté à une nouvelle marmite locale au lieu de la marmite d'origine qu'il a obtenue.

Beans: C'est le même concept que les objets (comme illustré ci-dessus) . Les beans sont essentiellement Objects en Java. Cependant, les beans (JavaBeans) sont utilisés dans diverses applications comme un moyen pratique de stocker et de transmettre une collection définie de données connexes. Tout comme le addVegetables pourrait gâcher le processus de cuisson en créant un nouveau pot de cuisson StringBuilder et en le jetant avec le chou-fleur, il pourrait également faire de même avec un pot de cuisson JavaBean .

6
ADTC

Je pense que cela peut être un détail superflu, que ce soit final ou non est un détail de mise en œuvre.

(Un peu comme déclarer des méthodes/membres dans une interface comme publics.)

2
Peter